Bug 1253137 - Baldr: update section header structure to match BinaryEncoding.md, part 1 (r=sunfish)

MozReview-Commit-ID: 41Yhj7esXsj
This commit is contained in:
Luke Wagner 2016-03-02 21:48:05 -06:00
Родитель cdd46d9e49
Коммит e87faa365d
4 изменённых файлов: 137 добавлений и 179 удалений

Просмотреть файл

@ -624,40 +624,6 @@ DecodeExpr(FunctionDecoder& f, ExprType expected)
return f.fail("bad expression code");
}
static bool
DecodeFuncBody(JSContext* cx, Decoder& d, ModuleGenerator& mg, FunctionGenerator& fg,
uint32_t funcIndex)
{
const uint8_t* bodyBegin = d.currentPosition();
FunctionDecoder f(cx, d, mg, fg, funcIndex);
uint32_t numExprs;
if (!d.readVarU32(&numExprs))
return Fail(cx, d, "expected number of function body expressions");
if (numExprs) {
for (size_t i = 0; i < numExprs - 1; i++) {
if (!DecodeExpr(f, ExprType::Void))
return false;
}
if (!DecodeExpr(f, f.ret()))
return false;
} else {
if (!CheckType(f, ExprType::Void, f.ret()))
return false;
}
const uint8_t* bodyEnd = d.currentPosition();
uintptr_t bodyLength = bodyEnd - bodyBegin;
if (!fg.bytecode().resize(bodyLength))
return false;
memcpy(fg.bytecode().begin(), bodyBegin, bodyLength);
return true;
}
/*****************************************************************************/
// dynamic link data
@ -684,12 +650,11 @@ typedef HashSet<const DeclaredSig*, SigHashPolicy> SigSet;
static bool
DecodeSignatureSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
{
if (!d.readCStringIf(SigLabel))
return true;
uint32_t sectionStart;
if (!d.startSection(&sectionStart))
return Fail(cx, d, "expected signature section byte size");
if (!d.startSection(SigLabel, &sectionStart))
return Fail(cx, d, "failed to start section");
if (sectionStart == Decoder::NotStarted)
return true;
uint32_t numSigs;
if (!d.readVarU32(&numSigs))
@ -762,12 +727,11 @@ DecodeSignatureIndex(JSContext* cx, Decoder& d, const ModuleGeneratorData& init,
static bool
DecodeDeclarationSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
{
if (!d.readCStringIf(DeclLabel))
return true;
uint32_t sectionStart;
if (!d.startSection(&sectionStart))
return Fail(cx, d, "expected decl section byte size");
if (!d.startSection(DeclLabel, &sectionStart))
return Fail(cx, d, "failed to start section");
if (sectionStart == Decoder::NotStarted)
return true;
uint32_t numDecls;
if (!d.readVarU32(&numDecls))
@ -793,12 +757,11 @@ DecodeDeclarationSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
static bool
DecodeTableSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
{
if (!d.readCStringIf(TableLabel))
return true;
uint32_t sectionStart;
if (!d.startSection(&sectionStart))
return Fail(cx, d, "expected table section byte size");
if (!d.startSection(TableLabel, &sectionStart))
return Fail(cx, d, "failed to start section");
if (sectionStart == Decoder::NotStarted)
return true;
if (!d.readVarU32(&init->numTableElems))
return Fail(cx, d, "expected number of table elems");
@ -894,12 +857,11 @@ DecodeImport(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVec
static bool
DecodeImportSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* importNames)
{
if (!d.readCStringIf(ImportLabel))
return true;
uint32_t sectionStart;
if (!d.startSection(&sectionStart))
return Fail(cx, d, "expected import section byte size");
if (!d.startSection(ImportLabel, &sectionStart))
return Fail(cx, d, "failed to start section");
if (sectionStart == Decoder::NotStarted)
return true;
for (uint32_t i = 0; !d.readCStringIf(EndLabel); i++) {
if (i >= MaxImports)
@ -922,12 +884,12 @@ static bool
DecodeMemorySection(JSContext* cx, Decoder& d, ModuleGenerator& mg,
MutableHandle<ArrayBufferObject*> heap)
{
if (!d.readCStringIf(MemoryLabel))
uint32_t sectionStart;
if (!d.startSection(MemoryLabel, &sectionStart))
return Fail(cx, d, "failed to start section");
if (sectionStart == Decoder::NotStarted)
return true;
uint32_t sectionStart;
if (!d.startSection(&sectionStart))
return Fail(cx, d, "expected memory section byte size");
if (!d.readCStringIf(InitialLabel))
return Fail(cx, d, "expected memory section initial field");
@ -1016,12 +978,11 @@ DecodeMemoryExport(JSContext* cx, Decoder& d, ModuleGenerator& mg, CStringSet* d
static bool
DecodeExportsSection(JSContext* cx, Decoder& d, ModuleGenerator& mg)
{
if (!d.readCStringIf(ExportLabel))
return true;
uint32_t sectionStart;
if (!d.startSection(&sectionStart))
return Fail(cx, d, "expected export section byte size");
if (!d.startSection(ExportLabel, &sectionStart))
return Fail(cx, d, "failed to start section");
if (sectionStart == Decoder::NotStarted)
return true;
CStringSet dupSet(cx);
if (!dupSet.init())
@ -1049,7 +1010,7 @@ DecodeExportsSection(JSContext* cx, Decoder& d, ModuleGenerator& mg)
}
static bool
DecodeFunctionSection(JSContext* cx, Decoder& d, ModuleGenerator& mg, uint32_t funcIndex)
DecodeFunctionBody(JSContext* cx, Decoder& d, ModuleGenerator& mg, uint32_t funcIndex)
{
int64_t before = PRMJ_Now();
@ -1057,10 +1018,6 @@ DecodeFunctionSection(JSContext* cx, Decoder& d, ModuleGenerator& mg, uint32_t f
if (!mg.startFuncDef(d.currentOffset(), &fg))
return false;
uint32_t sectionStart;
if (!d.startSection(&sectionStart))
return Fail(cx, d, "expected func section byte size");
const DeclaredSig& sig = mg.funcSig(funcIndex);
for (ValType type : sig.args()) {
if (!fg.addLocal(type))
@ -1079,11 +1036,33 @@ DecodeFunctionSection(JSContext* cx, Decoder& d, ModuleGenerator& mg, uint32_t f
return false;
}
if (!DecodeFuncBody(cx, d, mg, fg, funcIndex))
const uint8_t* bodyBegin = d.currentPosition();
FunctionDecoder f(cx, d, mg, fg, funcIndex);
uint32_t numExprs;
if (!d.readVarU32(&numExprs))
return Fail(cx, d, "expected number of function body expressions");
if (numExprs) {
for (size_t i = 0; i < numExprs - 1; i++) {
if (!DecodeExpr(f, ExprType::Void))
return false;
}
if (!DecodeExpr(f, f.ret()))
return false;
} else {
if (!CheckType(f, ExprType::Void, f.ret()))
return false;
}
const uint8_t* bodyEnd = d.currentPosition();
uintptr_t bodyLength = bodyEnd - bodyBegin;
if (!fg.bytecode().resize(bodyLength))
return false;
if (!d.finishSection(sectionStart))
return Fail(cx, d, "func section byte size mismatch");
memcpy(fg.bytecode().begin(), bodyBegin, bodyLength);
int64_t after = PRMJ_Now();
unsigned generateTime = (after - before) / PRMJ_USEC_PER_MSEC;
@ -1092,43 +1071,45 @@ DecodeFunctionSection(JSContext* cx, Decoder& d, ModuleGenerator& mg, uint32_t f
}
static bool
DecodeFunctionSections(JSContext* cx, Decoder& d, ModuleGenerator& mg)
DecodeFunctionBodiesSection(JSContext* cx, Decoder& d, ModuleGenerator& mg)
{
if (!mg.startFuncDefs())
return false;
uint32_t funcIndex = 0;
uint32_t sectionStart;
if (!d.startSection(FuncLabel, &sectionStart))
return Fail(cx, d, "failed to start section");
for (; d.readCStringIf(FuncLabel); funcIndex++) {
if (funcIndex >= mg.numFuncSigs())
return Fail(cx, d, "more function definitions than declarations");
if (sectionStart == Decoder::NotStarted) {
if (mg.numFuncSigs() != 0)
return Fail(cx, d, "expected function bodies");
if (!DecodeFunctionSection(cx, d, mg, funcIndex))
return mg.finishFuncDefs();
}
for (uint32_t funcIndex = 0; funcIndex < mg.numFuncSigs(); funcIndex++) {
if (!DecodeFunctionBody(cx, d, mg, funcIndex))
return false;
}
if (funcIndex < mg.numFuncSigs())
return Fail(cx, d, "fewer function definitions than declarations");
if (!d.finishSection(sectionStart))
return Fail(cx, d, "function section byte size mismatch");
if (!mg.finishFuncDefs())
return false;
return true;
return mg.finishFuncDefs();
}
static bool
DecodeDataSection(JSContext* cx, Decoder& d, Handle<ArrayBufferObject*> heap)
{
if (!d.readCStringIf(DataLabel))
uint32_t sectionStart;
if (!d.startSection(DataLabel, &sectionStart))
return Fail(cx, d, "failed to start section");
if (sectionStart == Decoder::NotStarted)
return true;
if (!heap)
return Fail(cx, d, "data section requires a memory section");
uint32_t sectionStart;
if (!d.startSection(&sectionStart))
return Fail(cx, d, "expected data section byte size");
uint8_t* const heapBase = heap->dataPointer();
uint32_t const heapLength = heap->byteLength();
uint32_t prevEnd = 0;
@ -1165,31 +1146,6 @@ DecodeDataSection(JSContext* cx, Decoder& d, Handle<ArrayBufferObject*> heap)
return true;
}
static bool
DecodeUnknownSection(JSContext* cx, Decoder& d)
{
UniqueChars sectionName = d.readCString();
if (!sectionName)
return Fail(cx, d, "failed to read section name");
if (!strcmp(sectionName.get(), SigLabel) ||
!strcmp(sectionName.get(), ImportLabel) ||
!strcmp(sectionName.get(), DeclLabel) ||
!strcmp(sectionName.get(), TableLabel) ||
!strcmp(sectionName.get(), MemoryLabel) ||
!strcmp(sectionName.get(), ExportLabel) ||
!strcmp(sectionName.get(), FuncLabel) ||
!strcmp(sectionName.get(), DataLabel))
{
return Fail(cx, d, "known section out of order");
}
if (!d.skipSection())
return Fail(cx, d, "unable to skip unknown section");
return true;
}
static bool
DecodeModule(JSContext* cx, UniqueChars file, const uint8_t* bytes, uint32_t length,
ImportNameVector* importNames, UniqueExportMap* exportMap,
@ -1230,7 +1186,7 @@ DecodeModule(JSContext* cx, UniqueChars file, const uint8_t* bytes, uint32_t len
if (!DecodeExportsSection(cx, d, mg))
return false;
if (!DecodeFunctionSections(cx, d, mg))
if (!DecodeFunctionBodiesSection(cx, d, mg))
return false;
if (!DecodeDataSection(cx, d, heap))
@ -1239,8 +1195,8 @@ DecodeModule(JSContext* cx, UniqueChars file, const uint8_t* bytes, uint32_t len
CacheableCharsVector funcNames;
while (!d.readCStringIf(EndLabel)) {
if (!DecodeUnknownSection(cx, d))
return false;
if (!d.skipSection())
return Fail(cx, d, "unable to skip unknown section");
}
if (!d.done())

Просмотреть файл

@ -459,8 +459,9 @@ class Encoder
// require backpatching since the size of the section is only known at the
// end while the size's uint32 must be stored at the beginning.
MOZ_WARN_UNUSED_RESULT bool startSection(size_t* offset) {
return writePatchableVarU32(offset);
MOZ_WARN_UNUSED_RESULT bool startSection(const char* name, size_t* offset) {
return writePatchableVarU32(offset) &&
writeCString(name);
}
void finishSection(size_t offset) {
return patchVarU32(offset, bytecode_.length() - offset - varU32ByteLength(offset));
@ -684,10 +685,20 @@ class Decoder
// See "section" description in Encoder.
MOZ_WARN_UNUSED_RESULT bool startSection(uint32_t* startOffset) {
*startOffset = currentOffset();
uint32_t unused;
return readVarU32(&unused);
static const uint32_t NotStarted = UINT32_MAX;
MOZ_WARN_UNUSED_RESULT bool startSection(const char* name, uint32_t* startOffset) {
const uint8_t* before = cur_;
uint32_t numBytes;
if (!readVarU32(&numBytes) || bytesRemain() < numBytes)
return false;
if (!readCStringIf(name)) {
cur_ = before;
*startOffset = NotStarted;
return true;
}
*startOffset = before - beg_;
return true;
}
MOZ_WARN_UNUSED_RESULT bool finishSection(uint32_t startOffset) {
uint32_t currentOffset = cur_ - beg_;

Просмотреть файл

@ -3709,11 +3709,8 @@ EncodeSignatureSection(Encoder& e, WasmAstModule& module)
if (module.sigs().empty())
return true;
if (!e.writeCString(SigLabel))
return false;
size_t offset;
if (!e.startSection(&offset))
if (!e.startSection(SigLabel, &offset))
return false;
if (!e.writeVarU32(module.sigs().length()))
@ -3742,11 +3739,8 @@ EncodeDeclarationSection(Encoder& e, WasmAstModule& module)
if (module.funcs().empty())
return true;
if (!e.writeCString(DeclLabel))
return false;
size_t offset;
if (!e.startSection(&offset))
if (!e.startSection(DeclLabel, &offset))
return false;
if (!e.writeVarU32(module.funcs().length()))
@ -3790,11 +3784,8 @@ EncodeImportSection(Encoder& e, WasmAstModule& module)
if (module.imports().empty())
return true;
if (!e.writeCString(ImportLabel))
return false;
size_t offset;
if (!e.startSection(&offset))
if (!e.startSection(ImportLabel, &offset))
return false;
for (WasmAstImport* imp : module.imports()) {
@ -3817,11 +3808,8 @@ EncodeMemorySection(Encoder& e, WasmAstModule& module)
if (!module.maybeMemory())
return true;
if (!e.writeCString(MemoryLabel))
return false;
size_t offset;
if (!e.startSection(&offset))
if (!e.startSection(MemoryLabel, &offset))
return false;
WasmAstMemory& memory = *module.maybeMemory();
@ -3866,11 +3854,8 @@ EncodeExportSection(Encoder& e, WasmAstModule& module)
if (module.exports().empty())
return true;
if (!e.writeCString(ExportLabel))
return false;
size_t offset;
if (!e.startSection(&offset))
if (!e.startSection(ExportLabel, &offset))
return false;
for (WasmAstExport* exp : module.exports()) {
@ -3903,11 +3888,8 @@ EncodeTableSection(Encoder& e, WasmAstModule& module)
if (!module.maybeTable())
return true;
if (!e.writeCString(TableLabel))
return false;
size_t offset;
if (!e.startSection(&offset))
if (!e.startSection(TableLabel, &offset))
return false;
if (!e.writeVarU32(module.maybeTable()->elems().length()))
@ -3923,15 +3905,8 @@ EncodeTableSection(Encoder& e, WasmAstModule& module)
}
static bool
EncodeFunctionSection(Encoder& e, WasmAstFunc& func)
EncodeFunctionBody(Encoder& e, WasmAstFunc& func)
{
if (!e.writeCString(FuncLabel))
return false;
size_t offset;
if (!e.startSection(&offset))
return false;
if (!e.writeVarU32(func.vars().length()))
return false;
@ -3948,8 +3923,25 @@ EncodeFunctionSection(Encoder& e, WasmAstFunc& func)
return false;
}
e.finishSection(offset);
return true;
}
static bool
EncodeFunctionBodiesSection(Encoder& e, WasmAstModule& module)
{
if (module.funcs().empty())
return true;
size_t offset;
if (!e.startSection(FuncLabel, &offset))
return false;
for (WasmAstFunc* func : module.funcs()) {
if (!EncodeFunctionBody(e, *func))
return false;
}
e.finishSection(offset);
return true;
}
@ -3990,11 +3982,8 @@ EncodeDataSection(Encoder& e, WasmAstModule& module)
const WasmAstSegmentVector& segments = module.maybeMemory()->segments();
if (!e.writeCString(DataLabel))
return false;
size_t offset;
if (!e.startSection(&offset))
if (!e.startSection(DataLabel, &offset))
return false;
for (WasmAstSegment* segment : segments) {
@ -4044,10 +4033,8 @@ EncodeModule(WasmAstModule& module)
if (!EncodeExportSection(e, module))
return nullptr;
for (WasmAstFunc* func : module.funcs()) {
if (!EncodeFunctionSection(e, *func))
if (!EncodeFunctionBodiesSection(e, module))
return nullptr;
}
if (!EncodeDataSection(e, module))
return nullptr;

Просмотреть файл

@ -24,7 +24,7 @@ const dataLabel = "data";
const magicError = /failed to match magic number/;
const versionError = /failed to match binary version/;
const extraError = /failed to consume all bytes of module/;
const sectionError = /failed to read section name/;
const sectionError = /failed to start section/;
const I32Code = 0;
const I64Code = 1;
@ -75,8 +75,8 @@ function cstring(name) {
function moduleWithSections(sectionArray) {
var bytes = moduleHeaderThen();
for (let section of sectionArray) {
bytes.push(...varU32(section.name.length + 1 + section.body.length));
bytes.push(...cstring(section.name));
bytes.push(...varU32(section.body.length));
bytes.push(...section.body);
}
bytes.push(0);
@ -103,12 +103,16 @@ function declSection(decls) {
return { name: declLabel, body };
}
function funcSection(func) {
var body = [];
var locals = varU32(func.locals.length);
function funcBody(func) {
var body = varU32(func.locals.length);
for (let local of func.locals)
locals.push(...varU32(local));
body = body.concat(locals, func.body);
body.push(...varU32(local));
body.push(...varU32(func.body.length));
return body.concat(...func.body);
}
function bodySection(bodies) {
var body = [].concat(...bodies);
return { name: funcLabel, body };
}
@ -134,7 +138,7 @@ function tableSection(elems) {
const v2vSig = {args:[], ret:VoidCode};
const i2vSig = {args:[I32Code], ret:VoidCode};
const v2vFunc = funcSection({locals:[], body:[0]});
const v2vBody = funcBody({locals:[], body:[]});
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([ {name: sigLabel, body: U32MAX_LEB, } ]))), TypeError, /too many signatures/);
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([ {name: sigLabel, body: [1, ...U32MAX_LEB], } ]))), TypeError, /too many arguments in signature/);
@ -153,8 +157,8 @@ assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([sigSection([{args:[1
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([sigSection([]), declSection([0])]))), TypeError, /signature index out of range/);
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([1])]))), TypeError, /signature index out of range/);
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([0])]))), TypeError, /fewer function definitions than declarations/);
wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([0]), v2vFunc])));
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([0])]))), TypeError, /expected function bodies/);
wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([v2vBody])])));
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), {name: importLabel, body:[]}]))), TypeError);
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([importSection([{sigIndex:0, module:"a", func:"b"}])]))), TypeError, /signature index out of range/);
@ -166,14 +170,14 @@ wasmEval(toBuf(moduleWithSections([
sigSection([v2vSig]),
importSection([{sigIndex:0, module:"a", func:""}]),
declSection([0]),
v2vFunc])), {a:()=>{}});
bodySection([v2vBody])])), {a:()=>{}});
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([ {name: dataLabel, body: [], } ]))), TypeError, /data section requires a memory section/);
wasmEval(toBuf(moduleWithSections([tableSection([])])));
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([tableSection([0])]))), TypeError, /table element out of range/);
wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([0]), tableSection([0]), v2vFunc])));
wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([0]), tableSection([0,0]), v2vFunc])));
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([0]), tableSection([0,1]), v2vFunc]))), TypeError, /table element out of range/);
wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([0,0,0]), tableSection([0,1,0,2]), v2vFunc, v2vFunc, v2vFunc])));
wasmEval(toBuf(moduleWithSections([sigSection([v2vSig,i2vSig]), declSection([0,0,1]), tableSection([0,1,2]), v2vFunc, v2vFunc, v2vFunc])));
wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([0]), tableSection([0]), bodySection([v2vBody])])));
wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([0]), tableSection([0,0]), bodySection([v2vBody])])));
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([0]), tableSection([0,1]), bodySection([v2vBody])]))), TypeError, /table element out of range/);
wasmEval(toBuf(moduleWithSections([sigSection([v2vSig]), declSection([0,0,0]), tableSection([0,1,0,2]), bodySection([v2vBody, v2vBody, v2vBody])])));
wasmEval(toBuf(moduleWithSections([sigSection([v2vSig,i2vSig]), declSection([0,0,1]), tableSection([0,1,2]), bodySection([v2vBody, v2vBody, v2vBody])])));