summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-binary.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/wasm-binary.cpp')
-rw-r--r--src/wasm/wasm-binary.cpp84
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();
}