diff options
Diffstat (limited to 'src/wasm-binary.h')
-rw-r--r-- | src/wasm-binary.h | 178 |
1 files changed, 130 insertions, 48 deletions
diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 04bebddc5..40671b082 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -234,7 +234,7 @@ namespace BinaryConsts { enum Meta { Magic = 0x6d736100, - Version = 11 + Version = 0x0c }; namespace Section { @@ -412,6 +412,7 @@ enum ASTNodes { CallFunction = 0x16, CallIndirect = 0x17, CallImport = 0x18, + TeeLocal = 0x19, GetGlobal = 0x1a, SetGlobal = 0x1b, @@ -426,6 +427,7 @@ enum ASTNodes { TableSwitch = 0x08, Return = 0x09, Unreachable = 0x0a, + Drop = 0x0b, End = 0x0f }; @@ -529,8 +531,7 @@ public: if (debug) std::cerr << "== writeMemory" << std::endl; auto start = startSection(BinaryConsts::Section::Memory); o << U32LEB(wasm->memory.initial) - << U32LEB(wasm->memory.max) - << int8_t(wasm->memory.exportName.is()); // export memory + << U32LEB(wasm->memory.max); finishSection(start); } @@ -571,7 +572,14 @@ public: o << U32LEB(wasm->imports.size()); for (auto& import : wasm->imports) { if (debug) std::cerr << "write one" << std::endl; - o << U32LEB(getFunctionTypeIndex(import->type->name)); + o << U32LEB(import->kind); + switch (import->kind) { + case Export::Function: o << U32LEB(getFunctionTypeIndex(import->functionType->name)); + case Export::Table: break; + case Export::Memory: break; + case Export::Global: o << binaryWasmType(import->globalType);break; + default: WASM_UNREACHABLE(); + } writeInlineString(import->module.str); writeInlineString(import->base.str); } @@ -690,7 +698,14 @@ public: o << U32LEB(wasm->exports.size()); for (auto& curr : wasm->exports) { if (debug) std::cerr << "write one" << std::endl; - o << U32LEB(getFunctionIndex(curr->value)); + o << U32LEB(curr->kind); + switch (curr->kind) { + case Export::Function: o << U32LEB(getFunctionIndex(curr->value)); break; + case Export::Table: o << U32LEB(0); break; + case Export::Memory: o << U32LEB(0); break; + case Export::Global: o << U32LEB(getGlobalIndex(curr->value)); break; + default: WASM_UNREACHABLE(); + } writeInlineString(curr->name.str); } finishSection(start); @@ -726,7 +741,7 @@ public: return mappedImports[name]; } - std::map<Name, uint32_t> mappedFunctions; // name of the Function => index + std::map<Name, uint32_t> mappedFunctions; // name of the Function => index uint32_t getFunctionIndex(Name name) { if (!mappedFunctions.size()) { // Create name => index mapping. @@ -739,6 +754,26 @@ public: return mappedFunctions[name]; } + std::map<Name, uint32_t> mappedGlobals; // name of the Global => index. first imported globals, then internal globals + uint32_t getGlobalIndex(Name name) { + if (!mappedGlobals.size()) { + // Create name => index mapping. + for (auto& import : wasm->imports) { + if (import->kind != Import::Global) continue; + assert(mappedGlobals.count(import->name) == 0); + auto index = mappedGlobals.size(); + mappedGlobals[import->name] = index; + } + for (size_t i = 0; i < wasm->globals.size(); i++) { + assert(mappedGlobals.count(wasm->globals[i]->name) == 0); + auto index = mappedGlobals.size(); + mappedGlobals[wasm->globals[i]->name] = index; + } + } + assert(mappedGlobals.count(name)); + return mappedGlobals[name]; + } + void writeFunctionTable() { if (wasm->table.segments.size() == 0) return; if (debug) std::cerr << "== writeFunctionTable" << std::endl; @@ -873,11 +908,9 @@ public: void visitLoop(Loop *curr) { if (debug) std::cerr << "zz node: Loop" << std::endl; o << int8_t(BinaryConsts::Loop); - breakStack.push_back(curr->out); - breakStack.push_back(curr->in); + breakStack.push_back(curr->name); recursePossibleBlockContents(curr->body); breakStack.pop_back(); - breakStack.pop_back(); o << int8_t(BinaryConsts::End); } @@ -939,18 +972,18 @@ public: o << int8_t(BinaryConsts::GetLocal) << U32LEB(mappedLocals[curr->index]); } void visitSetLocal(SetLocal *curr) { - if (debug) std::cerr << "zz node: SetLocal" << std::endl; + if (debug) std::cerr << "zz node: Set|TeeLocal" << std::endl; recurse(curr->value); - o << int8_t(BinaryConsts::SetLocal) << U32LEB(mappedLocals[curr->index]); + o << int8_t(curr->isTee() ? BinaryConsts::TeeLocal : 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); + o << int8_t(BinaryConsts::GetGlobal) << U32LEB(getGlobalIndex(curr->name)); } void visitSetGlobal(SetGlobal *curr) { if (debug) std::cerr << "zz node: SetGlobal" << std::endl; recurse(curr->value); - o << int8_t(BinaryConsts::SetGlobal) << U32LEB(curr->index); + o << int8_t(BinaryConsts::SetGlobal) << U32LEB(getGlobalIndex(curr->name)); } void emitMemoryAccess(size_t alignment, size_t bytes, uint32_t offset) { @@ -991,7 +1024,7 @@ public: if (debug) std::cerr << "zz node: Store" << std::endl; recurse(curr->ptr); recurse(curr->value); - switch (curr->type) { + switch (curr->valueType) { case i32: { switch (curr->bytes) { case 1: o << int8_t(BinaryConsts::I32StoreMem8); break; @@ -1219,6 +1252,11 @@ public: if (debug) std::cerr << "zz node: Unreachable" << std::endl; o << int8_t(BinaryConsts::Unreachable); } + void visitDrop(Drop *curr) { + if (debug) std::cerr << "zz node: Drop" << std::endl; + recurse(curr->value); + o << int8_t(BinaryConsts::Drop); + } }; class WasmBinaryBuilder { @@ -1432,10 +1470,6 @@ public: if (debug) std::cerr << "== readMemory" << std::endl; wasm.memory.initial = getU32LEB(); wasm.memory.max = getU32LEB(); - auto exportMemory = getInt8(); - if (exportMemory) { - wasm.memory.exportName = Name("memory"); - } } void readSignatures() { @@ -1472,10 +1506,20 @@ public: if (debug) std::cerr << "read one" << std::endl; auto curr = new Import; curr->name = Name(std::string("import$") + std::to_string(i)); - auto index = getU32LEB(); - assert(index < wasm.functionTypes.size()); - curr->type = wasm.getFunctionType(index); - assert(curr->type->name.is()); + curr->kind = (Import::Kind)getU32LEB(); + switch (curr->kind) { + case Export::Function: { + auto index = getU32LEB(); + assert(index < wasm.functionTypes.size()); + curr->functionType = wasm.getFunctionType(index); + assert(curr->functionType->name.is()); + break; + } + case Export::Table: break; + case Export::Memory: break; + case Export::Global: curr->globalType = getWasmType(); break; + default: WASM_UNREACHABLE(); + } curr->module = getInlineString(); curr->base = getInlineString(); wasm.addImport(curr); @@ -1573,8 +1617,8 @@ public: for (size_t i = 0; i < num; i++) { if (debug) std::cerr << "read one" << std::endl; auto curr = new Export; + curr->kind = (Export::Kind)getU32LEB(); auto index = getU32LEB(); - assert(index < functionTypes.size()); curr->name = getInlineString(); exportIndexes[curr] = index; } @@ -1627,6 +1671,24 @@ public: return ret; } + std::map<Index, Name> mappedGlobals; // index of the Global => name. first imported globals, then internal globals + Name getGlobalName(Index index) { + if (!mappedGlobals.size()) { + // Create name => index mapping. + for (auto& import : wasm.imports) { + if (import->kind != Import::Global) continue; + auto index = mappedGlobals.size(); + mappedGlobals[index] = import->name; + } + for (size_t i = 0; i < wasm.globals.size(); i++) { + auto index = mappedGlobals.size(); + mappedGlobals[index] = wasm.globals[i]->name; + } + } + assert(mappedGlobals.count(index)); + return mappedGlobals[index]; + } + void processFunctions() { for (auto& func : functions) { wasm.addFunction(func); @@ -1639,7 +1701,13 @@ public: for (auto& iter : exportIndexes) { Export* curr = iter.first; - curr->value = wasm.functions[iter.second]->name; + switch (curr->kind) { + case Export::Function: curr->value = wasm.functions[iter.second]->name; break; + case Export::Table: curr->value = Name::fromInt(0); break; + case Export::Memory: curr->value = Name::fromInt(0); break; + case Export::Global: curr->value = getGlobalName(iter.second); break; + default: WASM_UNREACHABLE(); + } wasm.addExport(curr); } @@ -1728,13 +1796,15 @@ public: case BinaryConsts::CallImport: visitCallImport((curr = allocator.alloc<CallImport>())->cast<CallImport>()); break; case BinaryConsts::CallIndirect: visitCallIndirect((curr = allocator.alloc<CallIndirect>())->cast<CallIndirect>()); break; case BinaryConsts::GetLocal: visitGetLocal((curr = allocator.alloc<GetLocal>())->cast<GetLocal>()); break; - case BinaryConsts::SetLocal: visitSetLocal((curr = allocator.alloc<SetLocal>())->cast<SetLocal>()); break; + case BinaryConsts::TeeLocal: + case BinaryConsts::SetLocal: visitSetLocal((curr = allocator.alloc<SetLocal>())->cast<SetLocal>(), code); break; case BinaryConsts::GetGlobal: visitGetGlobal((curr = allocator.alloc<GetGlobal>())->cast<GetGlobal>()); break; case BinaryConsts::SetGlobal: visitSetGlobal((curr = allocator.alloc<SetGlobal>())->cast<SetGlobal>()); break; case BinaryConsts::Select: visitSelect((curr = allocator.alloc<Select>())->cast<Select>()); break; case BinaryConsts::Return: visitReturn((curr = allocator.alloc<Return>())->cast<Return>()); break; case BinaryConsts::Nop: visitNop((curr = allocator.alloc<Nop>())->cast<Nop>()); break; case BinaryConsts::Unreachable: visitUnreachable((curr = allocator.alloc<Unreachable>())->cast<Unreachable>()); break; + case BinaryConsts::Drop: visitDrop((curr = allocator.alloc<Drop>())->cast<Drop>()); break; case BinaryConsts::End: case BinaryConsts::Else: curr = nullptr; break; default: { @@ -1832,13 +1902,10 @@ public: } void visitLoop(Loop *curr) { if (debug) std::cerr << "zz node: Loop" << std::endl; - curr->out = getNextLabel(); - curr->in = getNextLabel(); - breakStack.push_back(curr->out); - breakStack.push_back(curr->in); + curr->name = getNextLabel(); + breakStack.push_back(curr->name); curr->body = getMaybeBlock(); breakStack.pop_back(); - breakStack.pop_back(); curr->finalize(); } @@ -1890,7 +1957,7 @@ public: WASM_UNUSED(arity); auto import = wasm.getImport(getU32LEB()); curr->target = import->name; - auto type = import->type; + auto type = import->functionType; assert(type); auto num = type->params.size(); assert(num == arity); @@ -1922,25 +1989,35 @@ public: assert(curr->index < currFunction->getNumLocals()); curr->type = currFunction->getLocalType(curr->index); } - void visitSetLocal(SetLocal *curr) { - if (debug) std::cerr << "zz node: SetLocal" << std::endl; + void visitSetLocal(SetLocal *curr, uint8_t code) { + if (debug) std::cerr << "zz node: Set|TeeLocal" << std::endl; curr->index = getU32LEB(); assert(curr->index < currFunction->getNumLocals()); curr->value = popExpression(); curr->type = curr->value->type; + curr->setTee(code == BinaryConsts::TeeLocal); } 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; + auto index = getU32LEB(); + curr->name = getGlobalName(index); + auto* global = wasm.checkGlobal(curr->name); + if (global) { + curr->type = global->type; + return; + } + auto* import = wasm.checkImport(curr->name); + if (import && import->kind == Import::Global) { + curr->type = import->globalType; + return; + } + throw ParseException("bad get_global"); } void visitSetGlobal(SetGlobal *curr) { if (debug) std::cerr << "zz node: SetGlobal" << std::endl; - curr->index = getU32LEB(); - assert(curr->index < wasm.globals.size()); + auto index = getU32LEB(); + curr->name = getGlobalName(index); curr->value = popExpression(); - curr->type = curr->value->type; } void readMemoryAccess(Address& alignment, size_t bytes, Address& offset) { @@ -1976,21 +2053,22 @@ public: bool maybeVisitStore(Expression*& out, uint8_t code) { Store* curr; switch (code) { - case BinaryConsts::I32StoreMem8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->type = i32; break; - case BinaryConsts::I32StoreMem16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->type = i32; break; - case BinaryConsts::I32StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->type = i32; break; - case BinaryConsts::I64StoreMem8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->type = i64; break; - case BinaryConsts::I64StoreMem16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->type = i64; break; - case BinaryConsts::I64StoreMem32: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->type = i64; break; - case BinaryConsts::I64StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->type = i64; break; - case BinaryConsts::F32StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->type = f32; break; - case BinaryConsts::F64StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->type = f64; break; + case BinaryConsts::I32StoreMem8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->valueType = i32; break; + case BinaryConsts::I32StoreMem16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->valueType = i32; break; + case BinaryConsts::I32StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = i32; break; + case BinaryConsts::I64StoreMem8: curr = allocator.alloc<Store>(); curr->bytes = 1; curr->valueType = i64; break; + case BinaryConsts::I64StoreMem16: curr = allocator.alloc<Store>(); curr->bytes = 2; curr->valueType = i64; break; + case BinaryConsts::I64StoreMem32: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = i64; break; + case BinaryConsts::I64StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->valueType = i64; break; + case BinaryConsts::F32StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 4; curr->valueType = f32; break; + case BinaryConsts::F64StoreMem: curr = allocator.alloc<Store>(); curr->bytes = 8; curr->valueType = f64; break; default: return false; } if (debug) std::cerr << "zz node: Store" << std::endl; readMemoryAccess(curr->align, curr->bytes, curr->offset); curr->value = popExpression(); curr->ptr = popExpression(); + curr->finalize(); out = curr; return true; } @@ -2175,6 +2253,10 @@ public: void visitUnreachable(Unreachable *curr) { if (debug) std::cerr << "zz node: Unreachable" << std::endl; } + void visitDrop(Drop *curr) { + if (debug) std::cerr << "zz node: Drop" << std::endl; + curr->value = popExpression(); + } }; } // namespace wasm |