Bug 1284155 - Baldr: allow data segments outside any memory definition (r=bbouvier)

MozReview-Commit-ID: B9QQLBvIVOs

--HG--
extra : rebase_source : 2e96bd2b7beb709e04f7ea5fdabec1736683efb1
This commit is contained in:
Luke Wagner 2016-07-08 14:45:39 -05:00
parent 5f945ff054
commit e6f8caae67
7 changed files with 98 additions and 38 deletions

View File

@ -587,14 +587,10 @@ typedef AstVector<AstSegment*> 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<AstImport*> ImportVector;
typedef AstVector<AstExport*> ExportVector;
typedef AstVector<AstSig*> SigVector;
typedef AstVector<AstSegment*> SegmentVector;
private:
typedef AstHashMap<AstSig*, uint32_t, AstSig> 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) {

View File

@ -1457,13 +1457,12 @@ AstDecodeDataSection(AstDecodeContext &c)
if (!c.d.startSection(DataSectionId, &sectionStart, &sectionSize))
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;

View File

@ -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;

View File

@ -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--;

View File

@ -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, &sectionStart, &sectionSize))
@ -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))

View File

@ -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;

View File

@ -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);