summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/wasm-binary.h134
-rw-r--r--src/wasm/wasm-binary.cpp340
2 files changed, 247 insertions, 227 deletions
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index d0482816e..ae71251bb 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -652,10 +652,79 @@ inline S32LEB binaryType(Type type) {
return S32LEB(ret);
}
-class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> {
+class WasmBinaryWriter;
+
+// Writes out binary format stack machine code for a Binaryen IR expression
+
+class StackWriter : public Visitor<StackWriter> {
+public:
+ // Without a function (offset for a global thing, etc.)
+ StackWriter(WasmBinaryWriter& parent, BufferWithRandomAccess& o, bool debug=false)
+ : func(nullptr), parent(parent), o(o), sourceMap(false), debug(debug) {}
+
+ // With a function - one is created for the entire function
+ StackWriter(Function* func, WasmBinaryWriter& parent, BufferWithRandomAccess& o, bool sourceMap=false, bool debug=false)
+ : func(func), parent(parent), o(o), sourceMap(sourceMap), debug(debug) {
+ mapLocals();
+ }
+
+ std::map<Type, size_t> numLocalsByType; // type => number of locals of that type in the compact form
+
+ // visits a node, emitting the proper code for it
+ void visit(Expression* curr);
+ // emits a node, but if it is a block with no name, emit a list of its contents
+ void visitPossibleBlockContents(Expression* curr);
+
+ void visitBlock(Block *curr);
+ void visitIf(If *curr);
+ void visitLoop(Loop *curr);
+ void visitBreak(Break *curr);
+ void visitSwitch(Switch *curr);
+ void visitCall(Call *curr);
+ void visitCallImport(CallImport *curr);
+ void visitCallIndirect(CallIndirect *curr);
+ void visitGetLocal(GetLocal *curr);
+ void visitSetLocal(SetLocal *curr);
+ void visitGetGlobal(GetGlobal *curr);
+ void visitSetGlobal(SetGlobal *curr);
+ void visitLoad(Load *curr);
+ void visitStore(Store *curr);
+ void visitAtomicRMW(AtomicRMW *curr);
+ void visitAtomicCmpxchg(AtomicCmpxchg *curr);
+ void visitAtomicWait(AtomicWait *curr);
+ void visitAtomicWake(AtomicWake *curr);
+ void visitConst(Const *curr);
+ void visitUnary(Unary *curr);
+ void visitBinary(Binary *curr);
+ void visitSelect(Select *curr);
+ void visitReturn(Return *curr);
+ void visitHost(Host *curr);
+ void visitNop(Nop *curr);
+ void visitUnreachable(Unreachable *curr);
+ void visitDrop(Drop *curr);
+
+private:
+ Function* func;
+ WasmBinaryWriter& parent;
+ BufferWithRandomAccess& o;
+ bool sourceMap;
+ bool debug;
+
+ std::map<Index, size_t> mappedLocals; // local index => index in compact form of [all int32s][all int64s]etc
+
+ std::vector<Name> breakStack;
+
+ int32_t getBreakIndex(Name name);
+ void emitMemoryAccess(size_t alignment, size_t bytes, uint32_t offset);
+
+ void mapLocals();
+};
+
+// Writes out wasm to the binary format
+
+class WasmBinaryWriter {
Module* wasm;
BufferWithRandomAccess& o;
- Function* currFunction = nullptr;
bool debug;
bool debugInfo = true;
std::ostream* sourceMap = nullptr;
@@ -664,6 +733,9 @@ class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> {
MixedArena allocator;
+ Function::DebugLocation lastDebugLocation;
+ size_t lastBytecodeOffset;
+
void prepare();
public:
WasmBinaryWriter(Module* input, BufferWithRandomAccess& o, bool debug = false) : wasm(input), o(o), debug(debug) {
@@ -703,10 +775,6 @@ public:
int32_t getFunctionTypeIndex(Name type);
void writeImports();
- std::map<Index, size_t> mappedLocals; // local index => index in compact form of [all int32s][all int64s]etc
- std::map<Type, size_t> numLocalsByType; // type => number of locals of that type in the compact form
-
- void mapLocals(Function* function);
void writeFunctionSignatures();
void writeExpression(Expression* curr);
void writeFunctions();
@@ -728,7 +796,7 @@ public:
void writeSourceMapProlog();
void writeSourceMapEpilog();
- void writeDebugLocation(size_t offset, const Function::DebugLocation& loc);
+ void writeDebugLocation(Expression* curr, Function* func);
// helpers
void writeInlineString(const char* name);
@@ -746,58 +814,6 @@ public:
void emitBuffer(const char* data, size_t size);
void emitString(const char *str);
void finishUp();
-
- // AST writing via visitors
- int depth = 0; // only for debugging
-
- void recurse(Expression* curr);
- std::vector<Name> breakStack;
- Function::DebugLocation lastDebugLocation;
- size_t lastBytecodeOffset;
-
- void visit(Expression* curr) {
- if (sourceMap && currFunction) {
- // Dump the sourceMap debug info
- auto& debugLocations = currFunction->debugLocations;
- auto iter = debugLocations.find(curr);
- if (iter != debugLocations.end() && iter->second != lastDebugLocation) {
- writeDebugLocation(o.size(), iter->second);
- }
- }
- Visitor<WasmBinaryWriter>::visit(curr);
- }
-
- void visitBlock(Block *curr);
- // emits a node, but if it is a block with no name, emit a list of its contents
- void recursePossibleBlockContents(Expression* curr);
- void visitIf(If *curr);
- void visitLoop(Loop *curr);
- int32_t getBreakIndex(Name name);
- void visitBreak(Break *curr);
- void visitSwitch(Switch *curr);
- void visitCall(Call *curr);
- void visitCallImport(CallImport *curr);
- void visitCallIndirect(CallIndirect *curr);
- void visitGetLocal(GetLocal *curr);
- void visitSetLocal(SetLocal *curr);
- void visitGetGlobal(GetGlobal *curr);
- void visitSetGlobal(SetGlobal *curr);
- void emitMemoryAccess(size_t alignment, size_t bytes, uint32_t offset);
- void visitLoad(Load *curr);
- void visitStore(Store *curr);
- void visitAtomicRMW(AtomicRMW *curr);
- void visitAtomicCmpxchg(AtomicCmpxchg *curr);
- void visitAtomicWait(AtomicWait *curr);
- void visitAtomicWake(AtomicWake *curr);
- void visitConst(Const *curr);
- void visitUnary(Unary *curr);
- void visitBinary(Binary *curr);
- void visitSelect(Select *curr);
- void visitReturn(Return *curr);
- void visitHost(Host *curr);
- void visitNop(Nop *curr);
- void visitUnreachable(Unreachable *curr);
- void visitDrop(Drop *curr);
};
class WasmBinaryBuilder {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index a11a66227..673738455 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -197,42 +197,6 @@ void WasmBinaryWriter::writeImports() {
finishSection(start);
}
-void WasmBinaryWriter::mapLocals(Function* function) {
- for (Index i = 0; i < function->getNumParams(); i++) {
- size_t curr = mappedLocals.size();
- mappedLocals[i] = curr;
- }
- for (auto type : function->vars) {
- numLocalsByType[type]++;
- }
- std::map<Type, size_t> currLocalsByType;
- for (Index i = function->getVarIndexBase(); i < function->getNumLocals(); i++) {
- size_t index = function->getVarIndexBase();
- Type type = function->getLocalType(i);
- currLocalsByType[type]++; // increment now for simplicity, must decrement it in returns
- if (type == i32) {
- mappedLocals[i] = index + currLocalsByType[i32] - 1;
- continue;
- }
- index += numLocalsByType[i32];
- if (type == i64) {
- mappedLocals[i] = index + currLocalsByType[i64] - 1;
- continue;
- }
- index += numLocalsByType[i64];
- if (type == f32) {
- mappedLocals[i] = index + currLocalsByType[f32] - 1;
- continue;
- }
- index += numLocalsByType[f32];
- if (type == f64) {
- mappedLocals[i] = index + currLocalsByType[f64] - 1;
- continue;
- }
- abort();
- }
-}
-
void WasmBinaryWriter::writeFunctionSignatures() {
if (wasm->functions.size() == 0) return;
if (debug) std::cerr << "== writeFunctionSignatures" << std::endl;
@@ -246,9 +210,7 @@ void WasmBinaryWriter::writeFunctionSignatures() {
}
void WasmBinaryWriter::writeExpression(Expression* curr) {
- assert(depth == 0);
- recurse(curr);
- assert(depth == 0);
+ StackWriter(*this, o, debug).visit(curr);
}
void WasmBinaryWriter::writeFunctions() {
@@ -262,23 +224,20 @@ void WasmBinaryWriter::writeFunctions() {
size_t sizePos = writeU32LEBPlaceholder();
size_t start = o.size();
Function* function = wasm->functions[i].get();
- currFunction = function;
- mappedLocals.clear();
- numLocalsByType.clear();
if (debug) std::cerr << "writing" << function->name << std::endl;
- mapLocals(function);
+ StackWriter stackWriter(function, *this, o, sourceMap, debug);
o << U32LEB(
- (numLocalsByType[i32] ? 1 : 0) +
- (numLocalsByType[i64] ? 1 : 0) +
- (numLocalsByType[f32] ? 1 : 0) +
- (numLocalsByType[f64] ? 1 : 0)
+ (stackWriter.numLocalsByType[i32] ? 1 : 0) +
+ (stackWriter.numLocalsByType[i64] ? 1 : 0) +
+ (stackWriter.numLocalsByType[f32] ? 1 : 0) +
+ (stackWriter.numLocalsByType[f64] ? 1 : 0)
);
- if (numLocalsByType[i32]) o << U32LEB(numLocalsByType[i32]) << binaryType(i32);
- if (numLocalsByType[i64]) o << U32LEB(numLocalsByType[i64]) << binaryType(i64);
- if (numLocalsByType[f32]) o << U32LEB(numLocalsByType[f32]) << binaryType(f32);
- if (numLocalsByType[f64]) o << U32LEB(numLocalsByType[f64]) << binaryType(f64);
+ if (stackWriter.numLocalsByType[i32]) o << U32LEB(stackWriter.numLocalsByType[i32]) << binaryType(i32);
+ if (stackWriter.numLocalsByType[i64]) o << U32LEB(stackWriter.numLocalsByType[i64]) << binaryType(i64);
+ if (stackWriter.numLocalsByType[f32]) o << U32LEB(stackWriter.numLocalsByType[f32]) << binaryType(f32);
+ if (stackWriter.numLocalsByType[f64]) o << U32LEB(stackWriter.numLocalsByType[f64]) << binaryType(f64);
- recursePossibleBlockContents(function->body);
+ stackWriter.visitPossibleBlockContents(function->body);
o << int8_t(BinaryConsts::End);
size_t size = o.size() - start;
assert(size <= std::numeric_limits<uint32_t>::max());
@@ -292,7 +251,6 @@ void WasmBinaryWriter::writeFunctions() {
}
tableOfContents.functionBodies.emplace_back(function->name, sizePos + sizeFieldSize, size);
}
- currFunction = nullptr;
finishSection(start);
}
@@ -565,16 +523,22 @@ void WasmBinaryWriter::writeUserSections() {
}
}
-void WasmBinaryWriter::writeDebugLocation(size_t offset, const Function::DebugLocation& loc) {
- if (lastBytecodeOffset > 0) {
- *sourceMap << ",";
+void WasmBinaryWriter::writeDebugLocation(Expression* curr, Function* func) {
+ auto& debugLocations = func->debugLocations;
+ auto iter = debugLocations.find(curr);
+ if (iter != debugLocations.end() && iter->second != lastDebugLocation) {
+ auto offset = o.size();
+ auto& loc = iter->second;
+ if (lastBytecodeOffset > 0) {
+ *sourceMap << ",";
+ }
+ writeBase64VLQ(*sourceMap, int32_t(offset - lastBytecodeOffset));
+ writeBase64VLQ(*sourceMap, int32_t(loc.fileIndex - lastDebugLocation.fileIndex));
+ writeBase64VLQ(*sourceMap, int32_t(loc.lineNumber - lastDebugLocation.lineNumber));
+ writeBase64VLQ(*sourceMap, int32_t(loc.columnNumber - lastDebugLocation.columnNumber));
+ lastDebugLocation = loc;
+ lastBytecodeOffset = offset;
}
- writeBase64VLQ(*sourceMap, int32_t(offset - lastBytecodeOffset));
- writeBase64VLQ(*sourceMap, int32_t(loc.fileIndex - lastDebugLocation.fileIndex));
- writeBase64VLQ(*sourceMap, int32_t(loc.lineNumber - lastDebugLocation.lineNumber));
- writeBase64VLQ(*sourceMap, int32_t(loc.columnNumber - lastDebugLocation.columnNumber));
- lastDebugLocation = loc;
- lastBytecodeOffset = offset;
}
void WasmBinaryWriter::writeInlineString(const char* name) {
@@ -615,17 +579,73 @@ void WasmBinaryWriter::finishUp() {
}
}
-void WasmBinaryWriter::recurse(Expression* curr) {
- if (debug) std::cerr << "zz recurse into " << ++depth << " at " << o.size() << std::endl;
- visit(curr);
- if (debug) std::cerr << "zz recurse from " << depth-- << " at " << o.size() << std::endl;
+// StackWriter
+
+void StackWriter::mapLocals() {
+ for (Index i = 0; i < func->getNumParams(); i++) {
+ size_t curr = mappedLocals.size();
+ mappedLocals[i] = curr;
+ }
+ for (auto type : func->vars) {
+ numLocalsByType[type]++;
+ }
+ std::map<Type, size_t> currLocalsByType;
+ for (Index i = func->getVarIndexBase(); i < func->getNumLocals(); i++) {
+ size_t index = func->getVarIndexBase();
+ Type type = func->getLocalType(i);
+ currLocalsByType[type]++; // increment now for simplicity, must decrement it in returns
+ if (type == i32) {
+ mappedLocals[i] = index + currLocalsByType[i32] - 1;
+ continue;
+ }
+ index += numLocalsByType[i32];
+ if (type == i64) {
+ mappedLocals[i] = index + currLocalsByType[i64] - 1;
+ continue;
+ }
+ index += numLocalsByType[i64];
+ if (type == f32) {
+ mappedLocals[i] = index + currLocalsByType[f32] - 1;
+ continue;
+ }
+ index += numLocalsByType[f32];
+ if (type == f64) {
+ mappedLocals[i] = index + currLocalsByType[f64] - 1;
+ continue;
+ }
+ abort();
+ }
+}
+
+void StackWriter::visit(Expression* curr) {
+ if (sourceMap) {
+ parent.writeDebugLocation(curr, func);
+ }
+ Visitor<StackWriter>::visit(curr);
}
static bool brokenTo(Block* block) {
return block->name.is() && BranchUtils::BranchSeeker::hasNamed(block, block->name);
}
-void WasmBinaryWriter::visitBlock(Block *curr) {
+// emits a node, but if it is a block with no name, emit a list of its contents
+void StackWriter::visitPossibleBlockContents(Expression* curr) {
+ auto* block = curr->dynCast<Block>();
+ if (!block || brokenTo(block)) {
+ visit(curr);
+ return;
+ }
+ for (auto* child : block->list) {
+ visit(child);
+ }
+ if (block->type == unreachable && block->list.back()->type != unreachable) {
+ // similar to in visitBlock, here we could skip emitting the block itself,
+ // but must still end the 'block' (the contents, really) with an unreachable
+ o << int8_t(BinaryConsts::Unreachable);
+ }
+}
+
+void StackWriter::visitBlock(Block *curr) {
if (debug) std::cerr << "zz node: Block" << std::endl;
o << int8_t(BinaryConsts::Block);
o << binaryType(curr->type != unreachable ? curr->type : none);
@@ -633,7 +653,7 @@ void WasmBinaryWriter::visitBlock(Block *curr) {
Index i = 0;
for (auto* child : curr->list) {
if (debug) std::cerr << " " << size_t(curr) << "\n zz Block element " << i++ << std::endl;
- recurse(child);
+ visit(child);
}
breakStack.pop_back();
if (curr->type == unreachable) {
@@ -650,42 +670,25 @@ void WasmBinaryWriter::visitBlock(Block *curr) {
}
}
-// emits a node, but if it is a block with no name, emit a list of its contents
-void WasmBinaryWriter::recursePossibleBlockContents(Expression* curr) {
- auto* block = curr->dynCast<Block>();
- if (!block || brokenTo(block)) {
- recurse(curr);
- return;
- }
- for (auto* child : block->list) {
- recurse(child);
- }
- if (block->type == unreachable && block->list.back()->type != unreachable) {
- // similar to in visitBlock, here we could skip emitting the block itself,
- // but must still end the 'block' (the contents, really) with an unreachable
- o << int8_t(BinaryConsts::Unreachable);
- }
-}
-
-void WasmBinaryWriter::visitIf(If *curr) {
+void StackWriter::visitIf(If *curr) {
if (debug) std::cerr << "zz node: If" << std::endl;
if (curr->condition->type == unreachable) {
// this if-else is unreachable because of the condition, i.e., the condition
// does not exit. So don't emit the if, but do consume the condition
- recurse(curr->condition);
+ visit(curr->condition);
o << int8_t(BinaryConsts::Unreachable);
return;
}
- recurse(curr->condition);
+ visit(curr->condition);
o << int8_t(BinaryConsts::If);
o << binaryType(curr->type != unreachable ? curr->type : none);
breakStack.push_back(IMPOSSIBLE_CONTINUE); // the binary format requires this; we have a block if we need one; TODO: optimize
- recursePossibleBlockContents(curr->ifTrue); // TODO: emit block contents directly, if possible
+ visitPossibleBlockContents(curr->ifTrue); // TODO: emit block contents directly, if possible
breakStack.pop_back();
if (curr->ifFalse) {
o << int8_t(BinaryConsts::Else);
breakStack.push_back(IMPOSSIBLE_CONTINUE); // TODO ditto
- recursePossibleBlockContents(curr->ifFalse);
+ visitPossibleBlockContents(curr->ifFalse);
breakStack.pop_back();
}
o << int8_t(BinaryConsts::End);
@@ -698,12 +701,13 @@ void WasmBinaryWriter::visitIf(If *curr) {
o << int8_t(BinaryConsts::Unreachable);
}
}
-void WasmBinaryWriter::visitLoop(Loop *curr) {
+
+void StackWriter::visitLoop(Loop *curr) {
if (debug) std::cerr << "zz node: Loop" << std::endl;
o << int8_t(BinaryConsts::Loop);
o << binaryType(curr->type != unreachable ? curr->type : none);
breakStack.push_back(curr->name);
- recursePossibleBlockContents(curr->body);
+ visitPossibleBlockContents(curr->body);
breakStack.pop_back();
o << int8_t(BinaryConsts::End);
if (curr->type == unreachable) {
@@ -712,22 +716,12 @@ void WasmBinaryWriter::visitLoop(Loop *curr) {
}
}
-int32_t WasmBinaryWriter::getBreakIndex(Name name) { // -1 if not found
- for (int i = breakStack.size() - 1; i >= 0; i--) {
- if (breakStack[i] == name) {
- return breakStack.size() - 1 - i;
- }
- }
- std::cerr << "bad break: " << name << " in " << currFunction->name << std::endl;
- abort();
-}
-
-void WasmBinaryWriter::visitBreak(Break *curr) {
+void StackWriter::visitBreak(Break *curr) {
if (debug) std::cerr << "zz node: Break" << std::endl;
if (curr->value) {
- recurse(curr->value);
+ visit(curr->value);
}
- if (curr->condition) recurse(curr->condition);
+ if (curr->condition) visit(curr->condition);
o << int8_t(curr->condition ? BinaryConsts::BrIf : BinaryConsts::Br)
<< U32LEB(getBreakIndex(curr->name));
if (curr->condition && curr->type == unreachable) {
@@ -742,12 +736,12 @@ void WasmBinaryWriter::visitBreak(Break *curr) {
}
}
-void WasmBinaryWriter::visitSwitch(Switch *curr) {
+void StackWriter::visitSwitch(Switch *curr) {
if (debug) std::cerr << "zz node: Switch" << std::endl;
if (curr->value) {
- recurse(curr->value);
+ visit(curr->value);
}
- recurse(curr->condition);
+ visit(curr->condition);
if (!BranchUtils::isBranchReachable(curr)) {
// if the branch is not reachable, then it's dangerous to emit it, as
// wasm type checking rules are different, especially in unreachable
@@ -762,73 +756,68 @@ void WasmBinaryWriter::visitSwitch(Switch *curr) {
o << U32LEB(getBreakIndex(curr->default_));
}
-void WasmBinaryWriter::visitCall(Call *curr) {
+void StackWriter::visitCall(Call *curr) {
if (debug) std::cerr << "zz node: Call" << std::endl;
for (auto* operand : curr->operands) {
- recurse(operand);
+ visit(operand);
}
- o << int8_t(BinaryConsts::CallFunction) << U32LEB(getFunctionIndex(curr->target));
+ o << int8_t(BinaryConsts::CallFunction) << U32LEB(parent.getFunctionIndex(curr->target));
if (curr->type == unreachable) {
o << int8_t(BinaryConsts::Unreachable);
}
}
-void WasmBinaryWriter::visitCallImport(CallImport *curr) {
+void StackWriter::visitCallImport(CallImport *curr) {
if (debug) std::cerr << "zz node: CallImport" << std::endl;
for (auto* operand : curr->operands) {
- recurse(operand);
+ visit(operand);
}
- o << int8_t(BinaryConsts::CallFunction) << U32LEB(getFunctionIndex(curr->target));
+ o << int8_t(BinaryConsts::CallFunction) << U32LEB(parent.getFunctionIndex(curr->target));
}
-void WasmBinaryWriter::visitCallIndirect(CallIndirect *curr) {
+void StackWriter::visitCallIndirect(CallIndirect *curr) {
if (debug) std::cerr << "zz node: CallIndirect" << std::endl;
for (auto* operand : curr->operands) {
- recurse(operand);
+ visit(operand);
}
- recurse(curr->target);
+ visit(curr->target);
o << int8_t(BinaryConsts::CallIndirect)
- << U32LEB(getFunctionTypeIndex(curr->fullType))
+ << U32LEB(parent.getFunctionTypeIndex(curr->fullType))
<< U32LEB(0); // Reserved flags field
if (curr->type == unreachable) {
o << int8_t(BinaryConsts::Unreachable);
}
}
-void WasmBinaryWriter::visitGetLocal(GetLocal *curr) {
+void StackWriter::visitGetLocal(GetLocal *curr) {
if (debug) std::cerr << "zz node: GetLocal " << (o.size() + 1) << std::endl;
o << int8_t(BinaryConsts::GetLocal) << U32LEB(mappedLocals[curr->index]);
}
-void WasmBinaryWriter::visitSetLocal(SetLocal *curr) {
+void StackWriter::visitSetLocal(SetLocal *curr) {
if (debug) std::cerr << "zz node: Set|TeeLocal" << std::endl;
- recurse(curr->value);
+ visit(curr->value);
o << int8_t(curr->isTee() ? BinaryConsts::TeeLocal : BinaryConsts::SetLocal) << U32LEB(mappedLocals[curr->index]);
if (curr->type == unreachable) {
o << int8_t(BinaryConsts::Unreachable);
}
}
-void WasmBinaryWriter::visitGetGlobal(GetGlobal *curr) {
+void StackWriter::visitGetGlobal(GetGlobal *curr) {
if (debug) std::cerr << "zz node: GetGlobal " << (o.size() + 1) << std::endl;
- o << int8_t(BinaryConsts::GetGlobal) << U32LEB(getGlobalIndex(curr->name));
+ o << int8_t(BinaryConsts::GetGlobal) << U32LEB(parent.getGlobalIndex(curr->name));
}
-void WasmBinaryWriter::visitSetGlobal(SetGlobal *curr) {
+void StackWriter::visitSetGlobal(SetGlobal *curr) {
if (debug) std::cerr << "zz node: SetGlobal" << std::endl;
- recurse(curr->value);
- o << int8_t(BinaryConsts::SetGlobal) << U32LEB(getGlobalIndex(curr->name));
+ visit(curr->value);
+ o << int8_t(BinaryConsts::SetGlobal) << U32LEB(parent.getGlobalIndex(curr->name));
}
-void WasmBinaryWriter::emitMemoryAccess(size_t alignment, size_t bytes, uint32_t offset) {
- o << U32LEB(Log2(alignment ? alignment : bytes));
- o << U32LEB(offset);
-}
-
-void WasmBinaryWriter::visitLoad(Load *curr) {
+void StackWriter::visitLoad(Load *curr) {
if (debug) std::cerr << "zz node: Load" << std::endl;
- recurse(curr->ptr);
+ visit(curr->ptr);
if (!curr->isAtomic) {
switch (curr->type) {
case i32: {
@@ -889,10 +878,10 @@ void WasmBinaryWriter::visitLoad(Load *curr) {
emitMemoryAccess(curr->align, curr->bytes, curr->offset);
}
-void WasmBinaryWriter::visitStore(Store *curr) {
+void StackWriter::visitStore(Store *curr) {
if (debug) std::cerr << "zz node: Store" << std::endl;
- recurse(curr->ptr);
- recurse(curr->value);
+ visit(curr->ptr);
+ visit(curr->value);
if (!curr->isAtomic) {
switch (curr->valueType) {
case i32: {
@@ -951,12 +940,12 @@ void WasmBinaryWriter::visitStore(Store *curr) {
emitMemoryAccess(curr->align, curr->bytes, curr->offset);
}
-void WasmBinaryWriter::visitAtomicRMW(AtomicRMW *curr) {
+void StackWriter::visitAtomicRMW(AtomicRMW *curr) {
if (debug) std::cerr << "zz node: AtomicRMW" << std::endl;
- recurse(curr->ptr);
+ visit(curr->ptr);
// stop if the rest isn't reachable anyhow
if (curr->ptr->type == unreachable) return;
- recurse(curr->value);
+ visit(curr->value);
if (curr->value->type == unreachable) return;
if (curr->type == unreachable) {
@@ -1005,14 +994,14 @@ void WasmBinaryWriter::visitAtomicRMW(AtomicRMW *curr) {
emitMemoryAccess(curr->bytes, curr->bytes, curr->offset);
}
-void WasmBinaryWriter::visitAtomicCmpxchg(AtomicCmpxchg *curr) {
+void StackWriter::visitAtomicCmpxchg(AtomicCmpxchg *curr) {
if (debug) std::cerr << "zz node: AtomicCmpxchg" << std::endl;
- recurse(curr->ptr);
+ visit(curr->ptr);
// stop if the rest isn't reachable anyhow
if (curr->ptr->type == unreachable) return;
- recurse(curr->expected);
+ visit(curr->expected);
if (curr->expected->type == unreachable) return;
- recurse(curr->replacement);
+ visit(curr->replacement);
if (curr->replacement->type == unreachable) return;
if (curr->type == unreachable) {
@@ -1045,14 +1034,14 @@ void WasmBinaryWriter::visitAtomicCmpxchg(AtomicCmpxchg *curr) {
emitMemoryAccess(curr->bytes, curr->bytes, curr->offset);
}
-void WasmBinaryWriter::visitAtomicWait(AtomicWait *curr) {
+void StackWriter::visitAtomicWait(AtomicWait *curr) {
if (debug) std::cerr << "zz node: AtomicWait" << std::endl;
- recurse(curr->ptr);
+ visit(curr->ptr);
// stop if the rest isn't reachable anyhow
if (curr->ptr->type == unreachable) return;
- recurse(curr->expected);
+ visit(curr->expected);
if (curr->expected->type == unreachable) return;
- recurse(curr->timeout);
+ visit(curr->timeout);
if (curr->timeout->type == unreachable) return;
o << int8_t(BinaryConsts::AtomicPrefix);
@@ -1071,19 +1060,19 @@ void WasmBinaryWriter::visitAtomicWait(AtomicWait *curr) {
}
}
-void WasmBinaryWriter::visitAtomicWake(AtomicWake *curr) {
+void StackWriter::visitAtomicWake(AtomicWake *curr) {
if (debug) std::cerr << "zz node: AtomicWake" << std::endl;
- recurse(curr->ptr);
+ visit(curr->ptr);
// stop if the rest isn't reachable anyhow
if (curr->ptr->type == unreachable) return;
- recurse(curr->wakeCount);
+ visit(curr->wakeCount);
if (curr->wakeCount->type == unreachable) return;
o << int8_t(BinaryConsts::AtomicPrefix) << int8_t(BinaryConsts::AtomicWake);
emitMemoryAccess(4, 4, 0);
}
-void WasmBinaryWriter::visitConst(Const *curr) {
+void StackWriter::visitConst(Const *curr) {
if (debug) std::cerr << "zz node: Const" << curr << " : " << curr->type << std::endl;
switch (curr->type) {
case i32: {
@@ -1107,9 +1096,9 @@ void WasmBinaryWriter::visitConst(Const *curr) {
if (debug) std::cerr << "zz const node done.\n";
}
-void WasmBinaryWriter::visitUnary(Unary *curr) {
+void StackWriter::visitUnary(Unary *curr) {
if (debug) std::cerr << "zz node: Unary" << std::endl;
- recurse(curr->value);
+ visit(curr->value);
switch (curr->op) {
case ClzInt32: o << int8_t(BinaryConsts::I32Clz); break;
case CtzInt32: o << int8_t(BinaryConsts::I32Ctz); break;
@@ -1170,10 +1159,10 @@ void WasmBinaryWriter::visitUnary(Unary *curr) {
}
}
-void WasmBinaryWriter::visitBinary(Binary *curr) {
+void StackWriter::visitBinary(Binary *curr) {
if (debug) std::cerr << "zz node: Binary" << std::endl;
- recurse(curr->left);
- recurse(curr->right);
+ visit(curr->left);
+ visit(curr->right);
switch (curr->op) {
case AddInt32: o << int8_t(BinaryConsts::I32Add); break;
@@ -1262,26 +1251,26 @@ void WasmBinaryWriter::visitBinary(Binary *curr) {
}
}
-void WasmBinaryWriter::visitSelect(Select *curr) {
+void StackWriter::visitSelect(Select *curr) {
if (debug) std::cerr << "zz node: Select" << std::endl;
- recurse(curr->ifTrue);
- recurse(curr->ifFalse);
- recurse(curr->condition);
+ visit(curr->ifTrue);
+ visit(curr->ifFalse);
+ visit(curr->condition);
o << int8_t(BinaryConsts::Select);
if (curr->type == unreachable) {
o << int8_t(BinaryConsts::Unreachable);
}
}
-void WasmBinaryWriter::visitReturn(Return *curr) {
+void StackWriter::visitReturn(Return *curr) {
if (debug) std::cerr << "zz node: Return" << std::endl;
if (curr->value) {
- recurse(curr->value);
+ visit(curr->value);
}
o << int8_t(BinaryConsts::Return);
}
-void WasmBinaryWriter::visitHost(Host *curr) {
+void StackWriter::visitHost(Host *curr) {
if (debug) std::cerr << "zz node: Host" << std::endl;
switch (curr->op) {
case CurrentMemory: {
@@ -1289,7 +1278,7 @@ void WasmBinaryWriter::visitHost(Host *curr) {
break;
}
case GrowMemory: {
- recurse(curr->operands[0]);
+ visit(curr->operands[0]);
o << int8_t(BinaryConsts::GrowMemory);
break;
}
@@ -1298,22 +1287,37 @@ void WasmBinaryWriter::visitHost(Host *curr) {
o << U32LEB(0); // Reserved flags field
}
-void WasmBinaryWriter::visitNop(Nop *curr) {
+void StackWriter::visitNop(Nop *curr) {
if (debug) std::cerr << "zz node: Nop" << std::endl;
o << int8_t(BinaryConsts::Nop);
}
-void WasmBinaryWriter::visitUnreachable(Unreachable *curr) {
+void StackWriter::visitUnreachable(Unreachable *curr) {
if (debug) std::cerr << "zz node: Unreachable" << std::endl;
o << int8_t(BinaryConsts::Unreachable);
}
-void WasmBinaryWriter::visitDrop(Drop *curr) {
+void StackWriter::visitDrop(Drop *curr) {
if (debug) std::cerr << "zz node: Drop" << std::endl;
- recurse(curr->value);
+ visit(curr->value);
o << int8_t(BinaryConsts::Drop);
}
+int32_t StackWriter::getBreakIndex(Name name) { // -1 if not found
+ for (int i = breakStack.size() - 1; i >= 0; i--) {
+ if (breakStack[i] == name) {
+ return breakStack.size() - 1 - i;
+ }
+ }
+ std::cerr << "bad break: " << name << " in " << func->name << std::endl;
+ abort();
+}
+
+void StackWriter::emitMemoryAccess(size_t alignment, size_t bytes, uint32_t offset) {
+ o << U32LEB(Log2(alignment ? alignment : bytes));
+ o << U32LEB(offset);
+}
+
// reader
void WasmBinaryBuilder::read() {