summaryrefslogtreecommitdiff
path: root/src/wasm-binary.h
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2016-09-07 10:55:02 -0700
committerGitHub <noreply@github.com>2016-09-07 10:55:02 -0700
commit135a20cd110d356d5d098a08a7b447205adaed7a (patch)
treef5200a6b35f19d1bf95dea1fa7e339f40391413b /src/wasm-binary.h
parentfbe77b167002e8a49225b607ca8c37dc7e4b41fe (diff)
parentdd197d3212ac28e778d372df9d03e58b21386648 (diff)
downloadbinaryen-135a20cd110d356d5d098a08a7b447205adaed7a.tar.gz
binaryen-135a20cd110d356d5d098a08a7b447205adaed7a.tar.bz2
binaryen-135a20cd110d356d5d098a08a7b447205adaed7a.zip
Merge pull request #678 from WebAssembly/stack
Stack machine + 0xc update
Diffstat (limited to 'src/wasm-binary.h')
-rw-r--r--src/wasm-binary.h178
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