summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm/wasm-binary.cpp21
-rw-r--r--test/consume-stacky.wasmbin0 -> 40 bytes
-rw-r--r--test/consume-stacky.wasm.fromBinary16
3 files changed, 36 insertions, 1 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 43eb94601..aec2efe0e 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -2173,17 +2173,36 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
}
void WasmBinaryBuilder::pushBlockElements(Block* curr, size_t start, size_t end) {
+ // the first dropped element may be consumed by code later - it was on the stack first,
+ // and is the only thing left on the stack. there must be just one thing on the stack
+ // since we are at the end of a block context. note that we may need to drop more than
+ // one thing, since a bunch of concrete values may be all "consumed" by an unreachable
+ // (in which case, the first value can't be consumed anyhow, so it doesn't matter)
+ const Index NONE = -1;
+ Index consumable = NONE;
for (size_t i = start; i < end; i++) {
auto* item = expressionStack[i];
curr->list.push_back(item);
if (i < end - 1) {
// stacky&unreachable code may introduce elements that need to be dropped in non-final positions
if (isConcreteWasmType(item->type)) {
- curr->list.back() = Builder(wasm).makeDrop(curr->list.back());
+ curr->list.back() = Builder(wasm).makeDrop(item);
+ if (consumable == NONE) {
+ // this is the first, and hence consumable value. note the location
+ consumable = curr->list.size() - 1;
+ }
}
}
}
expressionStack.resize(start);
+ // if we have a consumable item and need it, use it
+ if (consumable != NONE && curr->list.back()->type == none) {
+ Builder builder(wasm);
+ auto* item = curr->list[consumable]->cast<Drop>()->value;
+ auto temp = builder.addVar(currFunction, item->type);
+ curr->list[consumable] = builder.makeSetLocal(temp, item);
+ curr->list.push_back(builder.makeGetLocal(temp, item->type));
+ }
}
void WasmBinaryBuilder::visitBlock(Block *curr) {
diff --git a/test/consume-stacky.wasm b/test/consume-stacky.wasm
new file mode 100644
index 000000000..8193dab45
--- /dev/null
+++ b/test/consume-stacky.wasm
Binary files differ
diff --git a/test/consume-stacky.wasm.fromBinary b/test/consume-stacky.wasm.fromBinary
new file mode 100644
index 000000000..b92d207b0
--- /dev/null
+++ b/test/consume-stacky.wasm.fromBinary
@@ -0,0 +1,16 @@
+(module
+ (type $0 (func (result i32)))
+ (memory $0 1 1)
+ (func $0 (; 0 ;) (type $0) (result i32)
+ (local $0 i32)
+ (set_local $0
+ (i32.const 1)
+ )
+ (i32.store
+ (i32.const 2)
+ (i32.const 3)
+ )
+ (get_local $0)
+ )
+)
+