diff options
-rw-r--r-- | src/wasm-binary.h | 7 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 27 | ||||
-rw-r--r-- | test/break-to-return.wasm | bin | 0 -> 51 bytes | |||
-rw-r--r-- | test/break-to-return.wasm.fromBinary | 16 |
4 files changed, 44 insertions, 6 deletions
diff --git a/src/wasm-binary.h b/src/wasm-binary.h index bc4a225df..3f5b799fe 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -695,8 +695,13 @@ public: Expression* readExpression(); void readGlobals(); - struct BreakTarget { Name name; int arity;}; + struct BreakTarget { + Name name; + int arity; + BreakTarget(Name name, int arity) : name(name), arity(arity) {} + }; std::vector<BreakTarget> breakStack; + bool breaksToReturn; // whether a break is done to the function scope, which is in effect a return std::vector<Expression*> expressionStack; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 26da1487f..65bf0a268 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -879,6 +879,9 @@ void WasmBinaryWriter::visitDrop(Drop *curr) { o << int8_t(BinaryConsts::Drop); } +// reader + +static Name RETURN_BREAK("binaryen|break-to-return"); void WasmBinaryBuilder::read() { @@ -1244,15 +1247,22 @@ void WasmBinaryBuilder::readFunctions() { // process the function body if (debug) std::cerr << "processing function: " << i << std::endl; nextLabel = 0; + breaksToReturn = false; // process body assert(breakStack.empty()); + breakStack.emplace_back(RETURN_BREAK, func->result != none); // the break target for the function scope assert(expressionStack.empty()); assert(depth == 0); func->body = getMaybeBlock(func->result); assert(depth == 0); - assert(breakStack.empty()); + assert(breakStack.size() == 1); + breakStack.pop_back(); assert(expressionStack.empty()); assert(pos == endOfFunction); + if (breaksToReturn) { + // we broke to return, so we need an outer block to break to + func->body = Builder(wasm).blockifyWithName(func->body, RETURN_BREAK); + } } currFunction = nullptr; functions.push_back(func); @@ -1609,10 +1619,17 @@ void WasmBinaryBuilder::visitLoop(Loop *curr) { } WasmBinaryBuilder::BreakTarget WasmBinaryBuilder::getBreakTarget(int32_t offset) { - if (debug) std::cerr << "getBreakTarget "<<offset<<std::endl; - assert(breakStack.size() - 1 - offset < breakStack.size()); - if (debug) std::cerr <<"breaktarget "<< breakStack[breakStack.size() - 1 - offset].name<< " arity "<<breakStack[breakStack.size() - 1 - offset].arity<< std::endl; - return breakStack[breakStack.size() - 1 - offset]; + if (debug) std::cerr << "getBreakTarget " << offset << std::endl; + size_t index = breakStack.size() - 1 - offset; + assert(index < breakStack.size()); + if (index == 0) { + // trying to access the topmost element means we break out + // to the function scope, doing in effect a return, we'll + // need to create a block for that. + breaksToReturn = true; + } + if (debug) std::cerr << "breaktarget "<< breakStack[index].name << " arity " << breakStack[index].arity << std::endl; + return breakStack[index]; } void WasmBinaryBuilder::visitBreak(Break *curr, uint8_t code) { diff --git a/test/break-to-return.wasm b/test/break-to-return.wasm Binary files differnew file mode 100644 index 000000000..233b993bb --- /dev/null +++ b/test/break-to-return.wasm diff --git a/test/break-to-return.wasm.fromBinary b/test/break-to-return.wasm.fromBinary new file mode 100644 index 000000000..cf5d2461d --- /dev/null +++ b/test/break-to-return.wasm.fromBinary @@ -0,0 +1,16 @@ +(module + (type $0 (func (param i32 i32) (result i32))) + (memory $0 256 256) + (export "add" (func $0)) + (func $0 (type $0) (param $var$0 i32) (param $var$1 i32) (result i32) + (block $binaryen|break-to-return i32 + (br $binaryen|break-to-return + (i32.add + (get_local $var$0) + (get_local $var$1) + ) + ) + ) + ) +) + |