diff --git a/js/src/asmjs/WasmAST.h b/js/src/asmjs/WasmAST.h index 7864c0a13676..4b74d1e35b5c 100644 --- a/js/src/asmjs/WasmAST.h +++ b/js/src/asmjs/WasmAST.h @@ -587,14 +587,10 @@ typedef AstVector AstSegmentVector; class AstMemory : public AstNode, public AstMemorySignature { - AstSegmentVector segments_; - public: - explicit AstMemory(AstMemorySignature memSig, AstSegmentVector&& segments) - : AstMemorySignature(memSig), - segments_(Move(segments)) + explicit AstMemory(AstMemorySignature memSig) + : AstMemorySignature(memSig) {} - const AstSegmentVector& segments() const { return segments_; } }; class AstModule : public AstNode @@ -604,12 +600,14 @@ class AstModule : public AstNode typedef AstVector ImportVector; typedef AstVector ExportVector; typedef AstVector SigVector; + typedef AstVector SegmentVector; private: typedef AstHashMap SigMap; LifoAlloc& lifo_; AstMemory* memory_; + SegmentVector segments_; SigVector sigs_; SigMap sigMap_; ImportVector imports_; @@ -621,6 +619,7 @@ class AstModule : public AstNode explicit AstModule(LifoAlloc& lifo) : lifo_(lifo), memory_(nullptr), + segments_(lifo), sigs_(lifo), sigMap_(lifo), imports_(lifo), @@ -640,6 +639,12 @@ class AstModule : public AstNode AstMemory* maybeMemory() const { return memory_; } + bool append(AstSegment* seg) { + return segments_.append(seg); + } + const SegmentVector& segments() const { + return segments_; + } bool declare(AstSig&& sig, uint32_t* sigIndex) { SigMap::AddPtr p = sigMap_.lookupForAdd(sig); if (p) { diff --git a/js/src/asmjs/WasmBinaryToAST.cpp b/js/src/asmjs/WasmBinaryToAST.cpp index 64358c928c87..1c7c9403e084 100644 --- a/js/src/asmjs/WasmBinaryToAST.cpp +++ b/js/src/asmjs/WasmBinaryToAST.cpp @@ -1457,13 +1457,12 @@ AstDecodeDataSection(AstDecodeContext &c) if (!c.d.startSection(DataSectionId, §ionStart, §ionSize)) return AstDecodeFail(c, "failed to start section"); - AstSegmentVector segments(c.lifo); if (sectionStart == Decoder::NotStarted) { if (!c.initialSizePages) return true; AstMemorySignature memSig(*c.initialSizePages, c.maxSizePages); - AstMemory* memory = new(c.lifo) AstMemory(memSig, Move(segments)); + AstMemory* memory = new(c.lifo) AstMemory(memSig); if (!memory) return false; @@ -1504,14 +1503,14 @@ AstDecodeDataSection(AstDecodeContext &c) AstName name(buffer, numBytes); AstSegment* segment = new(c.lifo) AstSegment(dstOffset, name); - if (!segment || !segments.append(segment)) + if (!segment || !c.module().append(segment)) return false; prevEnd = dstOffset + numBytes; } AstMemorySignature memSig(initialSizePages, c.maxSizePages); - AstMemory* memory = new(c.lifo) AstMemory(memSig, Move(segments)); + AstMemory* memory = new(c.lifo) AstMemory(memSig); if (!memory) return false; diff --git a/js/src/asmjs/WasmBinaryToExperimentalText.cpp b/js/src/asmjs/WasmBinaryToExperimentalText.cpp index bce251671049..271219553ab8 100644 --- a/js/src/asmjs/WasmBinaryToExperimentalText.cpp +++ b/js/src/asmjs/WasmBinaryToExperimentalText.cpp @@ -1616,7 +1616,7 @@ PrintCodeSection(WasmPrintContext& c, const AstModule::FuncVector& funcs, const static bool -PrintDataSection(WasmPrintContext& c, AstMemory* maybeMemory) +PrintDataSection(WasmPrintContext& c, AstMemory* maybeMemory, const AstModule::SegmentVector& segments) { if (!maybeMemory) return true; @@ -1636,7 +1636,7 @@ PrintDataSection(WasmPrintContext& c, AstMemory* maybeMemory) c.indent++; - uint32_t numSegments = maybeMemory->segments().length(); + uint32_t numSegments = segments.length(); if (!numSegments) { if (!c.buffer.append(" {}\n\n")) return false; @@ -1646,7 +1646,7 @@ PrintDataSection(WasmPrintContext& c, AstMemory* maybeMemory) return false; for (uint32_t i = 0; i < numSegments; i++) { - const AstSegment* segment = maybeMemory->segments()[i]; + const AstSegment* segment = segments[i]; if (!PrintIndent(c)) return false; @@ -1688,7 +1688,7 @@ PrintModule(WasmPrintContext& c, AstModule& module) if (!PrintCodeSection(c, module.funcs(), module.sigs())) return false; - if (!PrintDataSection(c, module.maybeMemory())) + if (!PrintDataSection(c, module.maybeMemory(), module.segments())) return false; return true; diff --git a/js/src/asmjs/WasmBinaryToText.cpp b/js/src/asmjs/WasmBinaryToText.cpp index e033d3ac3d84..7b0f8b82996f 100644 --- a/js/src/asmjs/WasmBinaryToText.cpp +++ b/js/src/asmjs/WasmBinaryToText.cpp @@ -1284,7 +1284,7 @@ RenderCodeSection(WasmRenderContext& c, const AstModule::FuncVector& funcs, cons static bool -RenderDataSection(WasmRenderContext& c, AstMemory* maybeMemory) +RenderDataSection(WasmRenderContext& c, AstMemory* maybeMemory, const AstModule::SegmentVector& segments) { if (!maybeMemory) return true; @@ -1305,7 +1305,7 @@ RenderDataSection(WasmRenderContext& c, AstMemory* maybeMemory) c.indent++; - uint32_t numSegments = maybeMemory->segments().length(); + uint32_t numSegments = segments.length(); if (!numSegments) { if (!c.buffer.append(")\n")) return false; @@ -1315,7 +1315,7 @@ RenderDataSection(WasmRenderContext& c, AstMemory* maybeMemory) return false; for (uint32_t i = 0; i < numSegments; i++) { - const AstSegment* segment = maybeMemory->segments()[i]; + const AstSegment* segment = segments[i]; if (!RenderIndent(c)) return false; @@ -1362,7 +1362,7 @@ RenderModule(WasmRenderContext& c, AstModule& module) if (!RenderCodeSection(c, module.funcs(), module.sigs())) return false; - if (!RenderDataSection(c, module.maybeMemory())) + if (!RenderDataSection(c, module.maybeMemory(), module.segments())) return false; c.indent--; diff --git a/js/src/asmjs/WasmCompile.cpp b/js/src/asmjs/WasmCompile.cpp index 5d63a530a5ba..14c7f3992bb0 100644 --- a/js/src/asmjs/WasmCompile.cpp +++ b/js/src/asmjs/WasmCompile.cpp @@ -1071,7 +1071,7 @@ DecodeCodeSection(Decoder& d, ModuleGenerator& mg) } static bool -DecodeDataSection(Decoder& d, ModuleGenerator& mg) +DecodeDataSection(Decoder& d, bool newFormat, ModuleGenerator& mg) { uint32_t sectionStart, sectionSize; if (!d.startSection(DataSectionId, §ionStart, §ionSize)) @@ -1091,8 +1091,23 @@ DecodeDataSection(Decoder& d, ModuleGenerator& mg) uint32_t max = mg.minMemoryLength(); for (uint32_t i = 0, prevEnd = 0; i < numSegments; i++) { - DataSegment seg; + if (newFormat) { + uint32_t linearMemoryIndex; + if (!d.readVarU32(&linearMemoryIndex)) + return Fail(d, "expected linear memory index"); + if (linearMemoryIndex != 0) + return Fail(d, "linear memory index must currently be 0"); + + Expr expr; + if (!d.readExpr(&expr)) + return Fail(d, "failed to read initializer expression"); + + if (expr != Expr::I32Const) + return Fail(d, "expected i32.const initializer expression"); + } + + DataSegment seg; if (!d.readVarU32(&seg.memoryOffset)) return Fail(d, "expected segment destination offset"); @@ -1247,7 +1262,7 @@ wasm::Compile(Bytes&& bytecode, CompileArgs&& args, UniqueChars* error) if (!DecodeCodeSection(d, mg)) return nullptr; - if (!DecodeDataSection(d, mg)) + if (!DecodeDataSection(d, newFormat, mg)) return nullptr; if (!DecodeNameSection(d, mg)) diff --git a/js/src/asmjs/WasmTextToBinary.cpp b/js/src/asmjs/WasmTextToBinary.cpp index f8dc76f1433b..9ccd0a9d350b 100644 --- a/js/src/asmjs/WasmTextToBinary.cpp +++ b/js/src/asmjs/WasmTextToBinary.cpp @@ -2341,9 +2341,6 @@ ParseTypeDef(WasmParseContext& c) static AstSegment* ParseSegment(WasmParseContext& c) { - if (!c.ts.match(WasmToken::Segment, c.error)) - return nullptr; - WasmToken dstOffset; if (!c.ts.match(WasmToken::Index, &dstOffset, c.error)) return nullptr; @@ -2372,22 +2369,23 @@ ParseMemorySignature(WasmParseContext& c, AstMemorySignature* memSig) } static AstMemory* -ParseMemory(WasmParseContext& c) +ParseMemory(WasmParseContext& c, AstModule* module) { AstMemorySignature memSig; if (!ParseMemorySignature(c, &memSig)) return nullptr; - AstSegmentVector segments(c.lifo); while (c.ts.getIf(WasmToken::OpenParen)) { + if (!c.ts.match(WasmToken::Segment, c.error)) + return nullptr; AstSegment* segment = ParseSegment(c); - if (!segment || !segments.append(segment)) + if (!segment || !module->append(segment)) return nullptr; if (!c.ts.match(WasmToken::CloseParen, c.error)) return nullptr; } - return new(c.lifo) AstMemory(memSig, Move(segments)); + return new(c.lifo) AstMemory(memSig); } static AstImport* @@ -2502,7 +2500,7 @@ ParseModule(const char16_t* text, LifoAlloc& lifo, UniqueChars* error) break; } case WasmToken::Memory: { - AstMemory* memory = ParseMemory(c); + AstMemory* memory = ParseMemory(c, module); if (!memory) return nullptr; if (!module->setMemory(memory)) { @@ -2511,6 +2509,16 @@ ParseModule(const char16_t* text, LifoAlloc& lifo, UniqueChars* error) } break; } + case WasmToken::Segment: { + AstSegment* segment = ParseSegment(c); + if (!segment) + return nullptr; + if (!module->append(segment)) { + c.ts.generateError(section, c.error); + return nullptr; + } + break; + } case WasmToken::Import: { AstImport* imp = ParseImport(c, module); if (!imp || !module->append(imp)) @@ -3677,8 +3685,16 @@ EncodeCodeSection(Encoder& e, AstModule& module) } static bool -EncodeDataSegment(Encoder& e, AstSegment& segment) +EncodeDataSegment(Encoder& e, bool newFormat, AstSegment& segment) { + if (newFormat) { + if (!e.writeVarU32(0)) // linear memory index + return false; + + if (!e.writeExpr(Expr::I32Const)) + return false; + } + if (!e.writeVarU32(segment.offset())) return false; @@ -3703,22 +3719,20 @@ EncodeDataSegment(Encoder& e, AstSegment& segment) } static bool -EncodeDataSection(Encoder& e, AstModule& module) +EncodeDataSection(Encoder& e, bool newFormat, AstModule& module) { - if (!module.maybeMemory() || module.maybeMemory()->segments().empty()) + if (module.segments().empty()) return true; - const AstSegmentVector& segments = module.maybeMemory()->segments(); - size_t offset; if (!e.startSection(DataSectionId, &offset)) return false; - if (!e.writeVarU32(segments.length())) + if (!e.writeVarU32(module.segments().length())) return false; - for (AstSegment* segment : segments) { - if (!EncodeDataSegment(e, *segment)) + for (AstSegment* segment : module.segments()) { + if (!EncodeDataSegment(e, newFormat, *segment)) return false; } @@ -3758,7 +3772,7 @@ EncodeModule(AstModule& module, bool newFormat, Bytes* bytes) if (!EncodeCodeSection(e, module)) return false; - if (!EncodeDataSection(e, module)) + if (!EncodeDataSection(e, newFormat, module)) return false; return true; diff --git a/js/src/jit-test/tests/wasm/import-export.js b/js/src/jit-test/tests/wasm/import-export.js index 64faf2f4be67..0f8820f50297 100644 --- a/js/src/jit-test/tests/wasm/import-export.js +++ b/js/src/jit-test/tests/wasm/import-export.js @@ -163,3 +163,30 @@ assertEq(mem, e.bar); assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 1 1)) (memory 1 1))')), TypeError, /already have default memory/); assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 1 1)) (import "x" "y" (memory 2 2)))')), TypeError, /already have default memory/); + +// Data segments on imports + +var m = new Module(textToBinary(` + (module + (import "a" "b" (memory 1 1)) + (segment 0 "\\0a\\0b") + (segment 100 "\\0c\\0d") + (func $get (param $p i32) (result i32) + (i32.load8_u (get_local $p))) + (export "get" $get)) +`)); +var mem = new Memory({initial:1}); +var {get} = new Instance(m, {a:{b:mem}}).exports; +assertEq(get(0), 0xa); +assertEq(get(1), 0xb); +assertEq(get(2), 0x0); +assertEq(get(100), 0xc); +assertEq(get(101), 0xd); +assertEq(get(102), 0x0); +var i8 = new Uint8Array(mem.buffer); +assertEq(i8[0], 0xa); +assertEq(i8[1], 0xb); +assertEq(i8[2], 0x0); +assertEq(i8[100], 0xc); +assertEq(i8[101], 0xd); +assertEq(i8[102], 0x0);