diff options
-rwxr-xr-x | check.py | 3 | ||||
-rw-r--r-- | src/wasm-binary.h | 399 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 45 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 5 |
4 files changed, 242 insertions, 210 deletions
@@ -445,7 +445,8 @@ for t in tests: print '\n[ checking wasm-shell spec testcases... ]\n' if len(requested) == 0: - BLACKLIST = ['memory.wast'] # FIXME we support old and new memory formats, for now, until 0xc, and so can't pass this old-style test + BLACKLIST = ['memory.wast', 'binary.wast'] # FIXME we support old and new memory formats, for now, until 0xc, and so can't pass this old-style test. + # FIXME to update the spec to 0xd, we need to implement (register "name") for import.wast spec_tests = [os.path.join('spec', t) for t in sorted(os.listdir(os.path.join(options.binaryen_test, 'spec'))) if t not in BLACKLIST] else: spec_tests = requested[:] diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 4110c9cd6..efff5a77b 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -270,7 +270,7 @@ namespace BinaryConsts { enum Meta { Magic = 0x6d736100, - Version = 0x0c + Version = 0x0d }; enum Section { @@ -288,8 +288,18 @@ enum Section { Data = 11 }; -enum ElementType { - AnyFunc = 0x20 +enum EncodedType { + // value_type + i32 = -0x1, // 0x7f + i64 = -0x2, // 0x7e + f32 = -0x3, // 0x7d + f64 = -0x4, // 0x7c + // elem_type + AnyFunc = -0x10, // 0x70 + // func_type form + Func = -0x20, // 0x60 + // block_type + Empty = -0x40 // 0x40 }; namespace UserSections { @@ -297,182 +307,196 @@ extern const char* Name; } enum ASTNodes { - CurrentMemory = 0x3b, - GrowMemory = 0x39, - I32Add = 0x40, - I32Sub = 0x41, - I32Mul = 0x42, - I32DivS = 0x43, - I32DivU = 0x44, - I32RemS = 0x45, - I32RemU = 0x46, - I32And = 0x47, - I32Or = 0x48, - I32Xor = 0x49, - I32Shl = 0x4a, - I32ShrU = 0x4b, - I32ShrS = 0x4c, - I32Eq = 0x4d, - I32Ne = 0x4e, - I32LtS = 0x4f, - I32LeS = 0x50, - I32LtU = 0x51, - I32LeU = 0x52, - I32GtS = 0x53, - I32GeS = 0x54, - I32GtU = 0x55, - I32GeU = 0x56, - I32Clz = 0x57, - I32Ctz = 0x58, - I32Popcnt = 0x59, - I32EqZ = 0x5a, - I64Add = 0x5b, - I64Sub = 0x5c, - I64Mul = 0x5d, - I64DivS = 0x5e, - I64DivU = 0x5f, - I64RemS = 0x60, - I64RemU = 0x61, - I64And = 0x62, - I64Or = 0x63, - I64Xor = 0x64, - I64Shl = 0x65, - I64ShrU = 0x66, - I64ShrS = 0x67, - I64Eq = 0x68, - I64Ne = 0x69, - I64LtS = 0x6a, - I64LeS = 0x6b, - I64LtU = 0x6c, - I64LeU = 0x6d, - I64GtS = 0x6e, - I64GeS = 0x6f, - I64GtU = 0x70, - I64GeU = 0x71, - I64Clz = 0x72, - I64Ctz = 0x73, - I64Popcnt = 0x74, - I64EqZ = 0xba, - F32Add = 0x75, - F32Sub = 0x76, - F32Mul = 0x77, - F32Div = 0x78, - F32Min = 0x79, - F32Max = 0x7a, - F32Abs = 0x7b, - F32Neg = 0x7c, - F32CopySign = 0x7d, - F32Ceil = 0x7e, - F32Floor = 0x7f, - F32Trunc = 0x80, - F32NearestInt = 0x81, - F32Sqrt = 0x82, - F32Eq = 0x83, - F32Ne = 0x84, - F32Lt = 0x85, - F32Le = 0x86, - F32Gt = 0x87, - F32Ge = 0x88, - F64Add = 0x89, - F64Sub = 0x8a, - F64Mul = 0x8b, - F64Div = 0x8c, - F64Min = 0x8d, - F64Max = 0x8e, - F64Abs = 0x8f, - F64Neg = 0x90, - F64CopySign = 0x91, - F64Ceil = 0x92, - F64Floor = 0x93, - F64Trunc = 0x94, - F64NearestInt = 0x95, - F64Sqrt = 0x96, - F64Eq = 0x97, - F64Ne = 0x98, - F64Lt = 0x99, - F64Le = 0x9a, - F64Gt = 0x9b, - F64Ge = 0x9c, - - I32STruncF32 = 0x9d, - I32STruncF64 = 0x9e, - I32UTruncF32 = 0x9f, - I32UTruncF64 = 0xa0, - I32ConvertI64 = 0xa1, - I64STruncF32 = 0xa2, - I64STruncF64 = 0xa3, - I64UTruncF32 = 0xa4, - I64UTruncF64 = 0xa5, - I64STruncI32 = 0xa6, - I64UTruncI32 = 0xa7, - F32SConvertI32 = 0xa8, - F32UConvertI32 = 0xa9, - F32SConvertI64 = 0xaa, - F32UConvertI64 = 0xab, - F32ConvertF64 = 0xac, - F32ReinterpretI32 = 0xad, - F64SConvertI32 = 0xae, - F64UConvertI32 = 0xaf, - F64SConvertI64 = 0xb0, - F64UConvertI64 = 0xb1, - F64ConvertF32 = 0xb2, - F64ReinterpretI64 = 0xb3, - I32ReinterpretF32 = 0xb4, - I64ReinterpretF64 = 0xb5, - I32RotR = 0xb6, - I32RotL = 0xb7, - I64RotR = 0xb8, - I64RotL = 0xb9, - - I32LoadMem8S = 0x20, - I32LoadMem8U = 0x21, - I32LoadMem16S = 0x22, - I32LoadMem16U = 0x23, - I64LoadMem8S = 0x24, - I64LoadMem8U = 0x25, - I64LoadMem16S = 0x26, - I64LoadMem16U = 0x27, - I64LoadMem32S = 0x28, - I64LoadMem32U = 0x29, - I32LoadMem = 0x2a, - I64LoadMem = 0x2b, - F32LoadMem = 0x2c, - F64LoadMem = 0x2d, - I32StoreMem8 = 0x2e, - I32StoreMem16 = 0x2f, - I64StoreMem8 = 0x30, - I64StoreMem16 = 0x31, - I64StoreMem32 = 0x32, - I32StoreMem = 0x33, - I64StoreMem = 0x34, - F32StoreMem = 0x35, - F64StoreMem = 0x36, - - I32Const = 0x10, - I64Const = 0x11, - F64Const = 0x12, - F32Const = 0x13, - GetLocal = 0x14, - SetLocal = 0x15, - CallFunction = 0x16, - CallIndirect = 0x17, - TeeLocal = 0x19, - GetGlobal = 0xbb, - SetGlobal = 0xbc, - Unreachable = 0x00, - Block = 0x01, - Loop = 0x02, - If = 0x03, - Else = 0x04, - Select = 0x05, - Br = 0x06, - BrIf = 0x07, - TableSwitch = 0x08, - Return = 0x09, - Nop = 0x0a, - Drop = 0x0b, - End = 0x0f + Nop = 0x01, + Block = 0x02, + Loop = 0x03, + If = 0x04, + Else = 0x05, + + End = 0x0b, + Br = 0x0c, + BrIf = 0x0d, + TableSwitch = 0x0e, // TODO: Rename to BrTable + Return = 0x0f, + + CallFunction = 0x10, + CallIndirect = 0x11, + + Drop = 0x1a, + Select = 0x1b, + + GetLocal = 0x20, + SetLocal = 0x21, + TeeLocal = 0x22, + GetGlobal = 0x23, + SetGlobal = 0x24, + + + I32LoadMem = 0x28, + I64LoadMem = 0x29, + F32LoadMem = 0x2a, + F64LoadMem = 0x2b, + + I32LoadMem8S = 0x2c, + I32LoadMem8U = 0x2d, + I32LoadMem16S = 0x2e, + I32LoadMem16U = 0x2f, + I64LoadMem8S = 0x30, + I64LoadMem8U = 0x31, + I64LoadMem16S = 0x32, + I64LoadMem16U = 0x33, + I64LoadMem32S = 0x34, + I64LoadMem32U = 0x35, + + I32StoreMem = 0x36, + I64StoreMem = 0x37, + F32StoreMem = 0x38, + F64StoreMem = 0x39, + + I32StoreMem8 = 0x3a, + I32StoreMem16 = 0x3b, + I64StoreMem8 = 0x3c, + I64StoreMem16 = 0x3d, + I64StoreMem32 = 0x3e, + + CurrentMemory = 0x3f, + GrowMemory = 0x40, + + I32Const = 0x41, + I64Const = 0x42, + F32Const = 0x43, + F64Const = 0x44, + + I32EqZ = 0x45, + I32Eq = 0x46, + I32Ne = 0x47, + I32LtS = 0x48, + I32LtU = 0x49, + I32GtS = 0x4a, + I32GtU = 0x4b, + I32LeS = 0x4c, + I32LeU = 0x4d, + I32GeS = 0x4e, + I32GeU = 0x4f, + I64EqZ = 0x50, + I64Eq = 0x51, + I64Ne = 0x52, + I64LtS = 0x53, + I64LtU = 0x54, + I64GtS = 0x55, + I64GtU = 0x56, + I64LeS = 0x57, + I64LeU = 0x58, + I64GeS = 0x59, + I64GeU = 0x5a, + F32Eq = 0x5b, + F32Ne = 0x5c, + F32Lt = 0x5d, + F32Gt = 0x5e, + F32Le = 0x5f, + F32Ge = 0x60, + F64Eq = 0x61, + F64Ne = 0x62, + F64Lt = 0x63, + F64Gt = 0x64, + F64Le = 0x65, + F64Ge = 0x66, + + I32Clz = 0x67, + I32Ctz = 0x68, + I32Popcnt = 0x69, + I32Add = 0x6a, + I32Sub = 0x6b, + I32Mul = 0x6c, + I32DivS = 0x6d, + I32DivU = 0x6e, + I32RemS = 0x6f, + I32RemU = 0x70, + I32And = 0x71, + I32Or = 0x72, + I32Xor = 0x73, + I32Shl = 0x74, + I32ShrS = 0x75, + I32ShrU = 0x76, + I32RotL = 0x77, + I32RotR = 0x78, + + I64Clz = 0x79, + I64Ctz = 0x7a, + I64Popcnt = 0x7b, + I64Add = 0x7c, + I64Sub = 0x7d, + I64Mul = 0x7e, + I64DivS = 0x7f, + I64DivU = 0x80, + I64RemS = 0x81, + I64RemU = 0x82, + I64And = 0x83, + I64Or = 0x84, + I64Xor = 0x85, + I64Shl = 0x86, + I64ShrS = 0x87, + I64ShrU = 0x88, + I64RotL = 0x89, + I64RotR = 0x8a, + + F32Abs = 0x8b, + F32Neg = 0x8c, + F32Ceil = 0x8d, + F32Floor = 0x8e, + F32Trunc = 0x8f, + F32NearestInt = 0x90, + F32Sqrt = 0x91, + F32Add = 0x92, + F32Sub = 0x93, + F32Mul = 0x94, + F32Div = 0x95, + F32Min = 0x96, + F32Max = 0x97, + F32CopySign = 0x98, + + F64Abs = 0x99, + F64Neg = 0x9a, + F64Ceil = 0x9b, + F64Floor = 0x9c, + F64Trunc = 0x9d, + F64NearestInt = 0x9e, + F64Sqrt = 0x9f, + F64Add = 0xa0, + F64Sub = 0xa1, + F64Mul = 0xa2, + F64Div = 0xa3, + F64Min = 0xa4, + F64Max = 0xa5, + F64CopySign = 0xa6, + + I32ConvertI64 = 0xa7, // TODO: rename to I32WrapI64 + I32STruncF32 = 0xa8, + I32UTruncF32 = 0xa9, + I32STruncF64 = 0xaa, + I32UTruncF64 = 0xab, + I64STruncI32 = 0xac, // TODO: rename to I64SExtendI32 + I64UTruncI32 = 0xad, // TODO: likewise + I64STruncF32 = 0xae, + I64UTruncF32 = 0xaf, + I64STruncF64 = 0xb0, + I64UTruncF64 = 0xb1, + F32SConvertI32 = 0xb2, + F32UConvertI32 = 0xb3, + F32SConvertI64 = 0xb4, + F32UConvertI64 = 0xb5, + F32ConvertF64 = 0xb6, // TODO: rename to F32DemoteI64 + F64SConvertI32 = 0xb7, + F64UConvertI32 = 0xb8, + F64SConvertI64 = 0xb9, + F64UConvertI64 = 0xba, + F64ConvertF32 = 0xbb, // TODO: rename to F64PromoteF32 + + I32ReinterpretF32 = 0xbc, + I64ReinterpretF64 = 0xbd, + F32ReinterpretI32 = 0xbe, + F64ReinterpretI64 = 0xbf }; enum MemoryAccess { @@ -481,22 +505,21 @@ enum MemoryAccess { NaturalAlignment = 0 }; -enum TypeForms { - Basic = 0x40 -}; - } // namespace BinaryConsts -inline int8_t binaryWasmType(WasmType type) { +inline S32LEB binaryWasmType(WasmType type) { + int ret; switch (type) { - case none: return 0; - case i32: return 1; - case i64: return 2; - case f32: return 3; - case f64: return 4; + // None only used for block signatures. TODO: Separate out? + case none: ret = BinaryConsts::EncodedType::Empty; break; + case i32: ret = BinaryConsts::EncodedType::i32; break; + case i64: ret = BinaryConsts::EncodedType::i64; break; + case f32: ret = BinaryConsts::EncodedType::f32; break; + case f64: ret = BinaryConsts::EncodedType::f64; break; default: abort(); } + return S32LEB(ret); } class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> { diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 74169fce2..d2a648294 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -103,7 +103,7 @@ void WasmBinaryWriter::writeTypes() { o << U32LEB(wasm->functionTypes.size()); for (auto& type : wasm->functionTypes) { if (debug) std::cerr << "write one" << std::endl; - o << int8_t(BinaryConsts::TypeForms::Basic); + o << S32LEB(BinaryConsts::EncodedType::Func); o << U32LEB(type->params.size()); for (auto param : type->params) { o << binaryWasmType(param); @@ -139,7 +139,7 @@ void WasmBinaryWriter::writeImports() { switch (import->kind) { case ExternalKind::Function: o << U32LEB(getFunctionTypeIndex(import->functionType->name)); break; case ExternalKind::Table: { - o << U32LEB(BinaryConsts::ElementType::AnyFunc); + o << S32LEB(BinaryConsts::EncodedType::AnyFunc); writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.max != Table::kMaxSize); break; } @@ -344,7 +344,7 @@ void WasmBinaryWriter::writeFunctionTableDeclaration() { if (debug) std::cerr << "== writeFunctionTableDeclaration" << std::endl; auto start = startSection(BinaryConsts::Section::Table); o << U32LEB(1); // Declare 1 table. - o << U32LEB(BinaryConsts::ElementType::AnyFunc); + o << S32LEB(BinaryConsts::EncodedType::AnyFunc); writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.max != Table::kMaxSize); finishSection(start); } @@ -533,7 +533,9 @@ void WasmBinaryWriter::visitCallIndirect(CallIndirect *curr) { recurse(operand); } recurse(curr->target); - o << int8_t(BinaryConsts::CallIndirect) << U32LEB(getFunctionTypeIndex(curr->fullType)); + o << int8_t(BinaryConsts::CallIndirect) + << U32LEB(getFunctionTypeIndex(curr->fullType)) + << U32LEB(0); // Reserved flags field } void WasmBinaryWriter::visitGetLocal(GetLocal *curr) { @@ -822,6 +824,7 @@ void WasmBinaryWriter::visitHost(Host *curr) { } default: abort(); } + o << U32LEB(0); // Reserved flags field } void WasmBinaryWriter::visitNop(Nop *curr) { @@ -976,13 +979,14 @@ int64_t WasmBinaryBuilder::getS64LEB() { } WasmType WasmBinaryBuilder::getWasmType() { - int8_t type = getInt8(); + int type = getS32LEB(); switch (type) { - case 0: return none; - case 1: return i32; - case 2: return i64; - case 3: return f32; - case 4: return f64; + // None only used for block signatures. TODO: Separate out? + case BinaryConsts::EncodedType::Empty: return none; + case BinaryConsts::EncodedType::i32: return i32; + case BinaryConsts::EncodedType::i64: return i64; + case BinaryConsts::EncodedType::f32: return f32; + case BinaryConsts::EncodedType::f64: return f64; default: abort(); } } @@ -1060,9 +1064,9 @@ void WasmBinaryBuilder::readSignatures() { for (size_t i = 0; i < numTypes; i++) { if (debug) std::cerr << "read one" << std::endl; auto curr = new FunctionType; - auto form = getU32LEB(); + auto form = getS32LEB(); WASM_UNUSED(form); - assert(form == BinaryConsts::TypeForms::Basic); + assert(form == BinaryConsts::EncodedType::Func); size_t numParams = getU32LEB(); if (debug) std::cerr << "num params: " << numParams << std::endl; for (size_t j = 0; j < numParams; j++) { @@ -1120,9 +1124,9 @@ void WasmBinaryBuilder::readImports() { break; } case ExternalKind::Table: { - auto elementType = getU32LEB(); + auto elementType = getS32LEB(); WASM_UNUSED(elementType); - if (elementType != BinaryConsts::ElementType::AnyFunc) throw ParseException("Imported table type is not AnyFunc"); + if (elementType != BinaryConsts::EncodedType::AnyFunc) throw ParseException("Imported table type is not AnyFunc"); wasm.table.exists = true; wasm.table.imported = true; getResizableLimits(wasm.table.initial, wasm.table.max, Table::kMaxSize); @@ -1358,8 +1362,8 @@ void WasmBinaryBuilder::readFunctionTableDeclaration() { if (numTables != 1) throw ParseException("Only 1 table definition allowed in MVP"); if (wasm.table.exists) throw ParseException("Table cannot be both imported and defined"); wasm.table.exists = true; - auto elemType = getU32LEB(); - if (elemType != BinaryConsts::ElementType::AnyFunc) throw ParseException("ElementType must be AnyFunc in MVP"); + auto elemType = getS32LEB(); + if (elemType != BinaryConsts::EncodedType::AnyFunc) throw ParseException("ElementType must be AnyFunc in MVP"); getResizableLimits(wasm.table.initial, wasm.table.max, Table::kMaxSize); } @@ -1535,7 +1539,7 @@ WasmBinaryBuilder::BreakTarget WasmBinaryBuilder::getBreakTarget(int32_t offset) } void WasmBinaryBuilder::visitBreak(Break *curr, uint8_t code) { - if (debug) std::cerr << "zz node: Break" << std::endl; + if (debug) std::cerr << "zz node: Break, code "<< int32_t(code) << std::endl; BreakTarget target = getBreakTarget(getU32LEB()); curr->name = target.name; if (code == BinaryConsts::BrIf) curr->condition = popExpression(); @@ -1587,6 +1591,8 @@ Expression* WasmBinaryBuilder::visitCall() { void WasmBinaryBuilder::visitCallIndirect(CallIndirect *curr) { if (debug) std::cerr << "zz node: CallIndirect" << std::endl; auto* fullType = wasm.functionTypes.at(getU32LEB()).get(); + auto reserved = getU32LEB(); + if (reserved != 0) throw ParseException("Invalid flags field in call_indirect"); curr->fullType = fullType->name; auto num = fullType->params.size(); curr->operands.resize(num); @@ -1693,6 +1699,7 @@ bool WasmBinaryBuilder::maybeVisitStore(Expression*& out, uint8_t code) { bool WasmBinaryBuilder::maybeVisitConst(Expression*& out, uint8_t code) { Const* curr; + if (debug) std::cerr << "zz node: Const, code " << code << std::endl; switch (code) { case BinaryConsts::I32Const: curr = allocator.alloc<Const>(); curr->value = Literal(getS32LEB()); break; case BinaryConsts::I64Const: curr = allocator.alloc<Const>(); curr->value = Literal(getS64LEB()); break; @@ -1702,7 +1709,7 @@ bool WasmBinaryBuilder::maybeVisitConst(Expression*& out, uint8_t code) { } curr->type = curr->value.type; out = curr; - if (debug) std::cerr << "zz node: Const" << std::endl; + return true; } @@ -1865,6 +1872,8 @@ bool WasmBinaryBuilder::maybeVisitHost(Expression*& out, uint8_t code) { default: return false; } if (debug) std::cerr << "zz node: Host" << std::endl; + auto reserved = getU32LEB(); + if (reserved != 0) throw ParseException("Invalid reserved field on grow_memory/current_memory"); curr->finalize(); out = curr; return true; diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index cbcdd5d3a..5898cc252 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -94,7 +94,7 @@ void Element::dump() { SExpressionParser::SExpressionParser(char* input) : input(input) { root = nullptr; - line = 0; + line = 1; lineStart = input; while (!root) { // keep parsing until we pass an initial comment root = parse(); @@ -138,7 +138,7 @@ void SExpressionParser::skipWhitespace() { if (input[0] == ';' && input[1] == ';') { while (input[0] && input[0] != '\n') input++; line++; - lineStart = input; + lineStart = ++input; } else if (input[0] == '(' && input[1] == ';') { // Skip nested block comments. input += 2; @@ -1438,7 +1438,6 @@ void SExpressionWasmBuilder::parseExport(Element& s) { if (inner[0]->str() == FUNC) { ex->kind = ExternalKind::Function; } else if (inner[0]->str() == MEMORY) { - if (!wasm.memory.exists) throw ParseException("memory exported but no memory"); ex->kind = ExternalKind::Memory; } else if (inner[0]->str() == TABLE) { ex->kind = ExternalKind::Table; |