diff options
Diffstat (limited to 'src/wasm/wasm-binary.cpp')
-rw-r--r-- | src/wasm/wasm-binary.cpp | 84 |
1 files changed, 67 insertions, 17 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 278a9ef44..3b48d9781 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -1087,6 +1087,11 @@ int64_t WasmBinaryBuilder::getS64LEB() { Type WasmBinaryBuilder::getType() { int type = getS32LEB(); + // Single value types are negative; signature indices are non-negative + if (type >= 0) { + // TODO: Handle block input types properly + return signatures[type].results; + } switch (type) { // None only used for block signatures. TODO: Separate out? case BinaryConsts::EncodedType::Empty: @@ -1699,7 +1704,7 @@ void WasmBinaryBuilder::processExpressions() { BYN_TRACE("== processExpressions finished\n"); return; } - expressionStack.push_back(curr); + pushExpression(curr); if (curr->type == Type::unreachable) { // Once we see something unreachable, we don't want to add anything else // to the stack, as it could be stacky code that is non-representable in @@ -1759,6 +1764,22 @@ void WasmBinaryBuilder::skipUnreachableCode() { expressionStack = savedStack; return; } + pushExpression(curr); + } +} + +void WasmBinaryBuilder::pushExpression(Expression* curr) { + if (curr->type.isMulti()) { + // Store tuple to local and push individual extracted values + Builder builder(wasm); + Index tuple = builder.addVar(currFunction, curr->type); + expressionStack.push_back(builder.makeLocalSet(tuple, curr)); + const std::vector<Type> types = curr->type.expand(); + for (Index i = 0; i < types.size(); ++i) { + expressionStack.push_back( + builder.makeTupleExtract(builder.makeLocalGet(tuple, curr->type), i)); + } + } else { expressionStack.push_back(curr); } } @@ -1778,6 +1799,7 @@ Expression* WasmBinaryBuilder::popExpression() { } // the stack is not empty, and we would not be going out of the current block auto ret = expressionStack.back(); + assert(!ret->type.isMulti()); expressionStack.pop_back(); return ret; } @@ -1818,6 +1840,35 @@ Expression* WasmBinaryBuilder::popNonVoidExpression() { return block; } +Expression* WasmBinaryBuilder::popTuple(size_t numElems) { + Builder builder(wasm); + std::vector<Expression*> elements; + elements.resize(numElems); + for (size_t i = 0; i < numElems; i++) { + auto* elem = popNonVoidExpression(); + if (elem->type == Type::unreachable) { + // All the previously-popped items cannot be reached, so ignore them. We + // cannot continue popping because there might not be enough items on the + // expression stack after an unreachable expression. Any remaining + // elements can stay unperturbed on the stack and will be explicitly + // dropped by some parent call to pushBlockElements. + return elem; + } + elements[numElems - i - 1] = elem; + } + return Builder(wasm).makeTupleMake(std::move(elements)); +} + +Expression* WasmBinaryBuilder::popTypedExpression(Type type) { + if (type.isSingle()) { + return popNonVoidExpression(); + } else if (type.isMulti()) { + return popTuple(type.size()); + } else { + WASM_UNREACHABLE("Invalid popped type"); + } +} + void WasmBinaryBuilder::validateBinary() { if (hasDataCount && wasm.memory.segments.size() != dataCount) { throwError("Number of segments does not agree with DataCount section"); @@ -2386,8 +2437,8 @@ void WasmBinaryBuilder::pushBlockElements(Block* curr, assert(start <= expressionStack.size()); // The results of this block are the last values pushed to the expressionStack Expression* results = nullptr; - if (type != Type::none) { - results = popNonVoidExpression(); + if (type.isConcrete()) { + results = popTypedExpression(type); } if (expressionStack.size() < start) { throwError("Block requires more values than are available"); @@ -2429,7 +2480,7 @@ void WasmBinaryBuilder::visitBlock(Block* curr) { while (1) { curr->type = getType(); curr->name = getNextLabel(); - breakStack.push_back({curr->name, curr->type != Type::none}); + breakStack.push_back({curr->name, curr->type}); stack.push_back(curr); if (more() && input[pos] == BinaryConsts::Block) { // a recursion @@ -2454,7 +2505,7 @@ void WasmBinaryBuilder::visitBlock(Block* curr) { size_t start = expressionStack.size(); if (last) { // the previous block is our first-position element - expressionStack.push_back(last); + pushExpression(last); } last = curr; processExpressions(); @@ -2478,14 +2529,13 @@ void WasmBinaryBuilder::visitBlock(Block* curr) { Expression* WasmBinaryBuilder::getBlockOrSingleton(Type type, unsigned numPops) { Name label = getNextLabel(); - breakStack.push_back( - {label, type != Type::none && type != Type::unreachable}); + breakStack.push_back({label, type}); auto start = expressionStack.size(); Builder builder(wasm); for (unsigned i = 0; i < numPops; i++) { auto* pop = builder.makePop(Type::exnref); - expressionStack.push_back(pop); + pushExpression(pop); } processExpressions(); @@ -2529,7 +2579,7 @@ void WasmBinaryBuilder::visitLoop(Loop* curr) { startControlFlow(curr); curr->type = getType(); curr->name = getNextLabel(); - breakStack.push_back({curr->name, 0}); + breakStack.push_back({curr->name, Type::none}); // find the expressions in the block, and create the body // a loop may have a list of instructions in wasm, much like // a block, but it only has a label at the top of the loop, @@ -2564,8 +2614,8 @@ WasmBinaryBuilder::getBreakTarget(int32_t offset) { if (index >= breakStack.size()) { throwError("bad breakindex (high)"); } - BYN_TRACE("breaktarget " << breakStack[index].name << " arity " - << breakStack[index].arity << std::endl); + BYN_TRACE("breaktarget " << breakStack[index].name << " type " + << breakStack[index].type << std::endl); auto& ret = breakStack[index]; // if the break is in literally unreachable code, then we will not emit it // anyhow, so do not note that the target has breaks to it @@ -2582,8 +2632,8 @@ void WasmBinaryBuilder::visitBreak(Break* curr, uint8_t code) { if (code == BinaryConsts::BrIf) { curr->condition = popNonVoidExpression(); } - if (target.arity) { - curr->value = popNonVoidExpression(); + if (target.type.isConcrete()) { + curr->value = popTypedExpression(target.type); } curr->finalize(); } @@ -2599,8 +2649,8 @@ void WasmBinaryBuilder::visitSwitch(Switch* curr) { auto defaultTarget = getBreakTarget(getU32LEB()); curr->default_ = defaultTarget.name; BYN_TRACE("default: " << curr->default_ << "\n"); - if (defaultTarget.arity) { - curr->value = popNonVoidExpression(); + if (defaultTarget.type.isConcrete()) { + curr->value = popTypedExpression(defaultTarget.type); } curr->finalize(); } @@ -4464,8 +4514,8 @@ void WasmBinaryBuilder::visitSelect(Select* curr, uint8_t code) { void WasmBinaryBuilder::visitReturn(Return* curr) { BYN_TRACE("zz node: Return\n"); requireFunctionContext("return"); - if (currFunction->sig.results != Type::none) { - curr->value = popNonVoidExpression(); + if (currFunction->sig.results.isConcrete()) { + curr->value = popTypedExpression(currFunction->sig.results); } curr->finalize(); } |