static bool DecodeImportSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* imports) { if (!d.readCStringIf(ImportSection)) return true; uint32_t sectionStart; if (!d.startSection(§ionStart)) return Fail(cx, d, "expected import section byte size"); uint32_t numImports; if (!d.readVarU32(&numImports)) return Fail(cx, d, "expected number of imports"); if (numImports > MaxImports) return Fail(cx, d, "too many imports"); for (uint32_t i = 0; i < numImports; i++) { if (!DecodeImport(cx, d, init, imports)) return false; } if (!d.finishSection(sectionStart)) return Fail(cx, d, "import section byte size mismatch"); return true; }
static bool DecodeExportTable(JSContext* cx, Decoder& d, ModuleGenerator& mg) { uint32_t sectionStart; if (!d.startSection(ExportTableId, §ionStart)) return Fail(cx, d, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; CStringSet dupSet(cx); if (!dupSet.init()) return false; uint32_t numExports; if (!d.readVarU32(&numExports)) return Fail(cx, d, "failed to read number of exports"); if (numExports > MaxExports) return Fail(cx, d, "too many exports"); for (uint32_t i = 0; i < numExports; i++) { if (!DecodeFunctionExport(cx, d, mg, &dupSet)) return false; } if (!d.finishSection(sectionStart)) return Fail(cx, d, "export section byte size mismatch"); return true; }
static bool DecodeDeclarationSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init) { if (!d.readCStringIf(DeclSection)) return true; uint32_t sectionStart; if (!d.startSection(§ionStart)) return Fail(cx, d, "expected decl section byte size"); uint32_t numDecls; if (!d.readVarU32(&numDecls)) return Fail(cx, d, "expected number of declarations"); if (numDecls > MaxFuncs) return Fail(cx, d, "too many functions"); if (!init->funcSigs.resize(numDecls)) return false; for (uint32_t i = 0; i < numDecls; i++) { if (!DecodeSignatureIndex(cx, d, *init, &init->funcSigs[i])) return false; } if (!d.finishSection(sectionStart)) return Fail(cx, d, "decls section byte size mismatch"); return true; }
static bool DecodeImportTable(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* importNames) { uint32_t sectionStart; if (!d.startSection(ImportTableId, §ionStart)) return Fail(cx, d, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; uint32_t numImports; if (!d.readVarU32(&numImports)) return Fail(cx, d, "failed to read number of imports"); if (numImports > MaxImports) return Fail(cx, d, "too many imports"); for (uint32_t i = 0; i < numImports; i++) { if (!DecodeImport(cx, d, init, importNames)) return false; } if (!d.finishSection(sectionStart)) return Fail(cx, d, "import section byte size mismatch"); return true; }
static bool DecodeExportsSection(JSContext* cx, Decoder& d, ModuleGenerator& mg) { if (!d.readCStringIf(ExportLabel)) return true; uint32_t sectionStart; if (!d.startSection(§ionStart)) return Fail(cx, d, "expected export section byte size"); CStringSet dupSet(cx); if (!dupSet.init()) return false; for (uint32_t i = 0; !d.readCStringIf(EndLabel); i++) { if (i >= MaxExports) return Fail(cx, d, "too many exports"); if (d.readCStringIf(FuncLabel)) { if (!DecodeFunctionExport(cx, d, mg, &dupSet)) return false; } else if (d.readCStringIf(MemoryLabel)) { if (!DecodeMemoryExport(cx, d, mg, &dupSet)) return false; } else { return Fail(cx, d, "unexpected export subsection"); } } if (!d.finishSection(sectionStart)) return Fail(cx, d, "export section byte size mismatch"); return true; }
static bool DecodeImportSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* importNames) { if (!d.readCStringIf(ImportLabel)) return true; uint32_t sectionStart; if (!d.startSection(§ionStart)) return Fail(cx, d, "expected import section byte size"); for (uint32_t i = 0; !d.readCStringIf(EndLabel); i++) { if (i >= MaxImports) return Fail(cx, d, "too many imports"); if (!d.readCStringIf(FuncLabel)) return Fail(cx, d, "expected 'func' import subsection"); if (!DecodeImport(cx, d, init, importNames)) return false; } if (!d.finishSection(sectionStart)) return Fail(cx, d, "import section byte size mismatch"); return true; }
static bool DecodeFunctionBodies(JSContext* cx, Decoder& d, ModuleGenerator& mg) { if (!mg.startFuncDefs()) return false; uint32_t sectionStart; if (!d.startSection(FunctionBodiesId, §ionStart)) return Fail(cx, d, "failed to start section"); if (sectionStart == Decoder::NotStarted) { if (mg.numFuncSigs() != 0) return Fail(cx, d, "expected function bodies"); return mg.finishFuncDefs(); } uint32_t numFuncBodies; if (!d.readVarU32(&numFuncBodies)) return Fail(cx, d, "expected function body count"); if (numFuncBodies != mg.numFuncSigs()) return Fail(cx, d, "function body count does not match function signature count"); for (uint32_t funcIndex = 0; funcIndex < numFuncBodies; funcIndex++) { if (!DecodeFunctionBody(cx, d, mg, funcIndex)) return false; } if (!d.finishSection(sectionStart)) return Fail(cx, d, "function section byte size mismatch"); return mg.finishFuncDefs(); }
static bool DecodeTableSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init) { if (!d.readCStringIf(TableLabel)) return true; uint32_t sectionStart; if (!d.startSection(§ionStart)) return Fail(cx, d, "expected table section byte size"); if (!d.readVarU32(&init->numTableElems)) return Fail(cx, d, "expected number of table elems"); if (init->numTableElems > MaxTableElems) return Fail(cx, d, "too many table elements"); Uint32Vector elems; if (!elems.resize(init->numTableElems)) return false; for (uint32_t i = 0; i < init->numTableElems; i++) { uint32_t funcIndex; if (!d.readVarU32(&funcIndex)) return Fail(cx, d, "expected table element"); if (funcIndex >= init->funcSigs.length()) return Fail(cx, d, "table element out of range"); elems[i] = funcIndex; } if (!d.finishSection(sectionStart)) return Fail(cx, d, "table section byte size mismatch"); // Convert the single (heterogeneous) indirect function table into an // internal set of asm.js-like homogeneous tables indexed by signature. // Every element in the heterogeneous table is present in only one // homogeneous table (as determined by its signature). An element's index in // the heterogeneous table is the same as its index in its homogeneous table // and all other homogeneous tables are given an entry that will fault if // called for at that element's index. for (uint32_t elemIndex = 0; elemIndex < elems.length(); elemIndex++) { uint32_t funcIndex = elems[elemIndex]; TableModuleGeneratorData& table = init->sigToTable[init->funcSigIndex(funcIndex)]; if (table.numElems == 0) { table.numElems = elems.length(); if (!table.elemFuncIndices.appendN(ModuleGenerator::BadIndirectCall, elems.length())) return false; } } for (uint32_t elemIndex = 0; elemIndex < elems.length(); elemIndex++) { uint32_t funcIndex = elems[elemIndex]; init->sigToTable[init->funcSigIndex(funcIndex)].elemFuncIndices[elemIndex] = funcIndex; } return true; }
static bool DecodeSignatureSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init) { if (!d.readCStringIf(SigSection)) return true; uint32_t sectionStart; if (!d.startSection(§ionStart)) return Fail(cx, d, "expected signature section byte size"); uint32_t numSigs; if (!d.readVarU32(&numSigs)) return Fail(cx, d, "expected number of signatures"); if (numSigs > MaxSigs) return Fail(cx, d, "too many signatures"); if (!init->sigs.resize(numSigs)) return false; for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) { uint32_t numArgs; if (!d.readVarU32(&numArgs)) return Fail(cx, d, "bad number of signature args"); if (numArgs > MaxArgsPerFunc) return Fail(cx, d, "too many arguments in signature"); ExprType result; if (!DecodeExprType(cx, d, &result)) return false; ValTypeVector args; if (!args.resize(numArgs)) return false; for (uint32_t i = 0; i < numArgs; i++) { if (!DecodeValType(cx, d, &args[i])) return false; } init->sigs[sigIndex] = Sig(Move(args), result); } if (!d.finishSection(sectionStart)) return Fail(cx, d, "decls section byte size mismatch"); return true; }
static bool DecodeDataSegments(JSContext* cx, Decoder& d, Handle<ArrayBufferObject*> heap) { uint32_t sectionStart; if (!d.startSection(DataSegmentsId, §ionStart)) 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 numSegments; if (!d.readVarU32(&numSegments)) return Fail(cx, d, "failed to read number of data segments"); uint8_t* const heapBase = heap->dataPointer(); uint32_t const heapLength = heap->byteLength(); uint32_t prevEnd = 0; for (uint32_t i = 0; i < numSegments; i++) { uint32_t dstOffset; if (!d.readVarU32(&dstOffset)) return Fail(cx, d, "expected segment destination offset"); if (dstOffset < prevEnd) return Fail(cx, d, "data segments must be disjoint and ordered"); uint32_t numBytes; if (!d.readVarU32(&numBytes)) return Fail(cx, d, "expected segment size"); if (dstOffset > heapLength || heapLength - dstOffset < numBytes) return Fail(cx, d, "data segment does not fit in memory"); const uint8_t* src; if (!d.readBytesRaw(numBytes, &src)) return Fail(cx, d, "data segment shorter than declared"); memcpy(heapBase + dstOffset, src, numBytes); prevEnd = dstOffset + numBytes; } if (!d.finishSection(sectionStart)) return Fail(cx, d, "data section byte size mismatch"); return true; }
static bool DecodeMemory(JSContext* cx, Decoder& d, ModuleGenerator& mg, MutableHandle<ArrayBufferObject*> heap) { uint32_t sectionStart; if (!d.startSection(MemoryId, §ionStart)) return Fail(cx, d, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; uint32_t initialSizePages; if (!d.readVarU32(&initialSizePages)) return Fail(cx, d, "expected initial memory size"); CheckedInt<int32_t> initialSize = initialSizePages; initialSize *= PageSize; if (!initialSize.isValid()) return Fail(cx, d, "initial memory size too big"); uint32_t maxSizePages; if (!d.readVarU32(&maxSizePages)) return Fail(cx, d, "expected initial memory size"); CheckedInt<int32_t> maxSize = maxSizePages; maxSize *= PageSize; if (!maxSize.isValid()) return Fail(cx, d, "initial memory size too big"); uint8_t exported; if (!d.readFixedU8(&exported)) return Fail(cx, d, "expected exported byte"); if (exported) { UniqueChars fieldName = DuplicateString("memory"); if (!fieldName || !mg.addMemoryExport(Move(fieldName))) return false; } if (!d.finishSection(sectionStart)) return Fail(cx, d, "memory section byte size mismatch"); bool signalsForOOB = CompileArgs(cx).useSignalHandlersForOOB; heap.set(ArrayBufferObject::createForWasm(cx, initialSize.value(), signalsForOOB)); if (!heap) return false; mg.initHeapUsage(HeapUsage::Unshared); return true; }
static bool DecodeFunc(JSContext* cx, Decoder& d, ModuleGenerator& mg, uint32_t funcIndex) { int64_t before = PRMJ_Now(); FunctionGenerator fg; if (!mg.startFuncDef(d.currentOffset(), &fg)) return false; if (!d.readCStringIf(FuncSubsection)) return Fail(cx, d, "expected 'func' tag"); uint32_t sectionStart; if (!d.startSection(§ionStart)) return Fail(cx, d, "expected func section byte size"); const DeclaredSig& sig = mg.funcSig(funcIndex); for (ValType type : sig.args()) { if (!fg.addLocal(type)) return false; } uint32_t numVars; if (!d.readVarU32(&numVars)) return Fail(cx, d, "expected number of local vars"); for (uint32_t i = 0; i < numVars; i++) { ValType type; if (!DecodeValType(cx, d, &type)) return false; if (!fg.addLocal(type)) return false; } if (!DecodeFuncBody(cx, d, mg, fg, funcIndex)) return false; if (!d.finishSection(sectionStart)) return Fail(cx, d, "func section byte size mismatch"); int64_t after = PRMJ_Now(); unsigned generateTime = (after - before) / PRMJ_USEC_PER_MSEC; return mg.finishFuncDef(funcIndex, generateTime, &fg); }
static bool DecodeMemorySection(JSContext* cx, Decoder& d, ModuleGenerator& mg, MutableHandle<ArrayBufferObject*> heap) { if (!d.readCStringIf(MemoryLabel)) return true; uint32_t sectionStart; if (!d.startSection(§ionStart)) return Fail(cx, d, "expected memory section byte size"); if (!d.readCStringIf(InitialLabel)) return Fail(cx, d, "expected memory section initial field"); uint32_t initialHeapSize; if (!d.readVarU32(&initialHeapSize)) return Fail(cx, d, "expected initial memory size"); if (initialHeapSize < PageSize || initialHeapSize % PageSize != 0) return Fail(cx, d, "initial memory size not a multiple of 0x10000"); if (initialHeapSize > INT32_MAX) return Fail(cx, d, "initial memory size too big"); if (!d.readCStringIf(EndLabel)) return Fail(cx, d, "expected end field of memory section"); if (!d.finishSection(sectionStart)) return Fail(cx, d, "memory section byte size mismatch"); bool signalsForOOB = CompileArgs(cx).useSignalHandlersForOOB; heap.set(ArrayBufferObject::createForWasm(cx, initialHeapSize, signalsForOOB)); if (!heap) return false; mg.initHeapUsage(HeapUsage::Unshared); return true; }
static bool DecodeExportsSection(JSContext* cx, Decoder& d, ModuleGenerator& mg, ExportMap* exportMap) { if (!d.readCStringIf(ExportSection)) return true; uint32_t sectionStart; if (!d.startSection(§ionStart)) return Fail(cx, d, "expected export section byte size"); uint32_t numExports; if (!d.readVarU32(&numExports)) return Fail(cx, d, "expected number of exports"); if (numExports > MaxExports) return Fail(cx, d, "too many exports"); for (uint32_t i = 0; i < numExports; i++) { if (!DecodeExport(cx, d, mg, exportMap)) return false; } if (!d.finishSection(sectionStart)) return Fail(cx, d, "export section byte size mismatch"); CStringSet dupSet(cx); if (!dupSet.init()) return false; for (const UniqueChars& prevName : exportMap->fieldNames) { CStringSet::AddPtr p = dupSet.lookupForAdd(prevName.get()); if (p) return Fail(cx, d, "duplicate export"); if (!dupSet.add(p, prevName.get())) return false; } return true; }
static bool DecodeCodeSection(JSContext* cx, Decoder& d, ModuleGenerator& mg) { if (!mg.startFuncDefs()) return false; uint32_t funcIndex = 0; while (d.readCStringIf(CodeSection)) { uint32_t sectionStart; if (!d.startSection(§ionStart)) return Fail(cx, d, "expected code section byte size"); uint32_t numFuncs; if (!d.readVarU32(&numFuncs)) return Fail(cx, d, "expected number of functions"); if (funcIndex + numFuncs > mg.numFuncSigs()) return Fail(cx, d, "more function definitions than declarations"); for (uint32_t i = 0; i < numFuncs; i++) { if (!DecodeFunc(cx, d, mg, funcIndex++)) return false; } if (!d.finishSection(sectionStart)) return Fail(cx, d, "code section byte size mismatch"); } if (funcIndex != mg.numFuncSigs()) return Fail(cx, d, "fewer function definitions than declarations"); if (!mg.finishFuncDefs()) return false; return true; }
bool finishSection(const SectionRange& range, const char* name) { return d_.finishSection(range, name); }
static bool DecodeSignatures(JSContext* cx, Decoder& d, ModuleGeneratorData* init) { uint32_t sectionStart; if (!d.startSection(SignaturesId, §ionStart)) return Fail(cx, d, "failed to start section"); if (sectionStart == Decoder::NotStarted) return true; uint32_t numSigs; if (!d.readVarU32(&numSigs)) return Fail(cx, d, "expected number of signatures"); if (numSigs > MaxSigs) return Fail(cx, d, "too many signatures"); if (!init->sigs.resize(numSigs)) return false; if (!init->sigToTable.resize(numSigs)) return false; SigSet dupSet(cx); if (!dupSet.init()) return false; for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) { uint32_t numArgs; if (!d.readVarU32(&numArgs)) return Fail(cx, d, "bad number of signature args"); if (numArgs > MaxArgsPerFunc) return Fail(cx, d, "too many arguments in signature"); ExprType result; if (!d.readExprType(&result)) return Fail(cx, d, "bad expression type"); if (!CheckExprType(cx, d, result)) return false; ValTypeVector args; if (!args.resize(numArgs)) return false; for (uint32_t i = 0; i < numArgs; i++) { if (!d.readValType(&args[i])) return Fail(cx, d, "bad value type"); if (!CheckValType(cx, d, args[i])) return false; } init->sigs[sigIndex] = Sig(Move(args), result); SigSet::AddPtr p = dupSet.lookupForAdd(init->sigs[sigIndex]); if (p) return Fail(cx, d, "duplicate signature"); if (!dupSet.add(p, &init->sigs[sigIndex])) return false; } if (!d.finishSection(sectionStart)) return Fail(cx, d, "decls section byte size mismatch"); return true; }