From 927c8256b113a9891d89833aa3e00374aa33e77c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 22 Jul 2016 10:49:34 -0700 Subject: [PATCH] binary support for wasm globals --- src/wasm-binary.h | 83 +++++++++++++++++++++++++++++++++++++++-------- src/wasm.cpp | 1 + 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/wasm-binary.h b/src/wasm-binary.h index e77f3992eec..bb2b9b1fce4 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -244,19 +244,13 @@ namespace Section { extern const char* FunctionSignatures; extern const char* Functions; extern const char* ExportTable; + extern const char* Globals; extern const char* DataSegments; extern const char* FunctionTable; extern const char* Names; extern const char* Start; }; -enum FunctionEntry { - Named = 1, - Import = 2, - Locals = 4, - Export = 8 -}; - enum ASTNodes { CurrentMemory = 0x3b, GrowMemory = 0x39, @@ -418,6 +412,8 @@ enum ASTNodes { CallFunction = 0x16, CallIndirect = 0x17, CallImport = 0x18, + GetGlobal = 0x1a, + SetGlobal = 0x1b, Nop = 0x00, Block = 0x01, @@ -486,6 +482,7 @@ class WasmBinaryWriter : public Visitor { writeFunctionSignatures(); writeFunctionTable(); writeMemory(); + writeGlobals(); writeExports(); writeStart(); writeFunctions(); @@ -632,6 +629,12 @@ class WasmBinaryWriter : public Visitor { finishSection(start); } + void writeExpression(Expression* curr) { + assert(depth == 0); + recurse(curr); + assert(depth == 0); + } + void writeFunctions() { if (wasm->functions.size() == 0) return; if (debug) std::cerr << "== writeFunctions" << std::endl; @@ -657,9 +660,7 @@ class WasmBinaryWriter : public Visitor { if (numLocalsByType[i64]) o << U32LEB(numLocalsByType[i64]) << binaryWasmType(i64); if (numLocalsByType[f32]) o << U32LEB(numLocalsByType[f32]) << binaryWasmType(f32); if (numLocalsByType[f64]) o << U32LEB(numLocalsByType[f64]) << binaryWasmType(f64); - depth = 0; - recurse(function->body); - assert(depth == 0); + writeExpression(function->body); size_t size = o.size() - start; assert(size <= std::numeric_limits::max()); if (debug) std::cerr << "body size: " << size << ", writing at " << sizePos << ", next starts at " << o.size() << std::endl; @@ -668,6 +669,20 @@ class WasmBinaryWriter : public Visitor { finishSection(start); } + void writeGlobals() { + if (wasm->globals.size() == 0) return; + if (debug) std::cerr << "== writeglobals" << std::endl; + auto start = startSection(BinaryConsts::Section::Globals); + o << U32LEB(wasm->globals.size()); + for (auto& curr : wasm->globals) { + if (debug) std::cerr << "write one" << std::endl; + o << binaryWasmType(curr->type); + writeExpression(curr->init); + o << int8_t(BinaryConsts::End); + } + finishSection(start); + } + void writeExports() { if (wasm->exports.size() == 0) return; if (debug) std::cerr << "== writeexports" << std::endl; @@ -797,7 +812,7 @@ class WasmBinaryWriter : public Visitor { // AST writing via visitors - int depth; // only for debugging + int depth = 0; // only for debugging void recurse(Expression*& curr) { if (debug) std::cerr << "zz recurse into " << ++depth << " at " << o.size() << std::endl; @@ -920,6 +935,15 @@ class WasmBinaryWriter : public Visitor { recurse(curr->value); o << int8_t(BinaryConsts::SetLocal) << U32LEB(mappedLocals[curr->index]); } + void visitGetGlobal(GetGlobal *curr) { + if (debug) std::cerr << "zz node: GetGlobal " << (o.size() + 1) << std::endl; + o << int8_t(BinaryConsts::GetGlobal) << U32LEB(curr->index); + } + void visitSetGlobal(SetGlobal *curr) { + if (debug) std::cerr << "zz node: SetGlobal" << std::endl; + recurse(curr->value); + o << int8_t(BinaryConsts::SetGlobal) << U32LEB(curr->index); + } void emitMemoryAccess(size_t alignment, size_t bytes, uint32_t offset) { o << U32LEB(Log2(alignment ? alignment : bytes)); @@ -1230,6 +1254,7 @@ class WasmBinaryBuilder { else if (match(BinaryConsts::Section::FunctionSignatures)) readFunctionSignatures(); else if (match(BinaryConsts::Section::Functions)) readFunctions(); else if (match(BinaryConsts::Section::ExportTable)) readExports(); + else if (match(BinaryConsts::Section::Globals)) readGlobals(); else if (match(BinaryConsts::Section::DataSegments)) readDataSegments(); else if (match(BinaryConsts::Section::FunctionTable)) readFunctionTable(); else if (match(BinaryConsts::Section::Names)) readNames(); @@ -1519,7 +1544,7 @@ class WasmBinaryBuilder { // process body assert(breakStack.empty()); assert(expressionStack.empty()); - depth = 0; + assert(depth == 0); func->body = getMaybeBlock(); assert(depth == 0); assert(breakStack.empty()); @@ -1547,6 +1572,23 @@ class WasmBinaryBuilder { } } + void readGlobals() { + if (debug) std::cerr << "== readGlobals" << std::endl; + size_t num = getU32LEB(); + if (debug) std::cerr << "num: " << num << std::endl; + for (size_t i = 0; i < num; i++) { + if (debug) std::cerr << "read one" << std::endl; + auto curr = new Global; + curr->type = getWasmType(); + assert(depth == 0); + processExpressions(); + assert(expressionStack.size() == 1); + curr->init = popExpression(); + assert(depth == 0); + wasm.addGlobal(curr); + } + } + std::vector breakStack; std::vector expressionStack; @@ -1643,7 +1685,7 @@ class WasmBinaryBuilder { // AST reading - int depth; // only for debugging + int depth = 0; // only for debugging BinaryConsts::ASTNodes readExpression(Expression*& curr) { if (pos == endOfFunction) { @@ -1665,6 +1707,8 @@ class WasmBinaryBuilder { case BinaryConsts::CallIndirect: visitCallIndirect((curr = allocator.alloc())->cast()); break; case BinaryConsts::GetLocal: visitGetLocal((curr = allocator.alloc())->cast()); break; case BinaryConsts::SetLocal: visitSetLocal((curr = allocator.alloc())->cast()); break; + case BinaryConsts::GetGlobal: visitGetGlobal((curr = allocator.alloc())->cast()); break; + case BinaryConsts::SetGlobal: visitSetGlobal((curr = allocator.alloc())->cast()); break; case BinaryConsts::Select: visitSelect((curr = allocator.alloc()); break; case BinaryConsts::Return: visitReturn((curr = allocator.alloc())->cast()); break; case BinaryConsts::Nop: visitNop((curr = allocator.alloc())->cast()); break; @@ -1863,6 +1907,19 @@ class WasmBinaryBuilder { curr->value = popExpression(); curr->type = curr->value->type; } + void visitGetGlobal(GetGlobal *curr) { + if (debug) std::cerr << "zz node: GetGlobal " << pos << std::endl; + curr->index = getU32LEB(); + assert(curr->index < wasm.globals.size()); + curr->type = wasm.globals[curr->index]->type; + } + void visitSetGlobal(SetGlobal *curr) { + if (debug) std::cerr << "zz node: SetGlobal" << std::endl; + curr->index = getU32LEB(); + assert(curr->index < wasm.globals.size()); + curr->value = popExpression(); + curr->type = curr->value->type; + } void readMemoryAccess(Address& alignment, size_t bytes, Address& offset) { alignment = Pow2(getU32LEB()); diff --git a/src/wasm.cpp b/src/wasm.cpp index 6732f9ca4a0..dbbd209b464 100644 --- a/src/wasm.cpp +++ b/src/wasm.cpp @@ -33,6 +33,7 @@ namespace Section { const char* FunctionSignatures = "function"; const char* Functions = "code"; const char* ExportTable = "export"; + const char* Globals = "global"; const char* DataSegments = "data"; const char* FunctionTable = "table"; const char* Names = "name";