bool ModuleGenerator::finishFuncExports() { // ModuleGenerator::exportedFuncs_ is an unordered HashSet. The // FuncExportVector stored in Metadata needs to be stored sorted by // function index to allow O(log(n)) lookup at runtime. Uint32Vector funcIndices; if (!funcIndices.reserve(exportedFuncs_.count())) return false; for (Uint32Set::Range r = exportedFuncs_.all(); !r.empty(); r.popFront()) funcIndices.infallibleAppend(r.front()); std::sort(funcIndices.begin(), funcIndices.end()); MOZ_ASSERT(metadata_->funcExports.empty()); if (!metadata_->funcExports.reserve(exportedFuncs_.count())) return false; for (uint32_t funcIndex : funcIndices) { Sig sig; if (!sig.clone(funcSig(funcIndex))) return false; metadata_->funcExports.infallibleEmplaceBack(Move(sig), funcIndex, funcIndexToCodeRange_[funcIndex]); } return true; }
bool ModuleGenerator::declareExport(UniqueChars fieldName, uint32_t funcIndex, uint32_t* exportIndex) { if (!exportMap_->fieldNames.append(Move(fieldName))) return false; FuncIndexMap::AddPtr p = funcIndexToExport_.lookupForAdd(funcIndex); if (p) { if (exportIndex) *exportIndex = p->value(); return exportMap_->fieldsToExports.append(p->value()); } uint32_t newExportIndex = module_->exports.length(); MOZ_ASSERT(newExportIndex < MaxExports); if (exportIndex) *exportIndex = newExportIndex; Sig copy; if (!copy.clone(funcSig(funcIndex))) return false; return module_->exports.append(Move(copy)) && funcIndexToExport_.add(p, funcIndex, newExportIndex) && exportMap_->fieldsToExports.append(newExportIndex) && exportMap_->exportFuncIndices.append(funcIndex); }
bool ModuleGenerator::addImport(const Sig& sig, uint32_t globalDataOffset) { Sig copy; if (!copy.clone(sig)) return false; return module_->imports.emplaceBack(Move(copy), globalDataOffset); }
bool ModuleGenerator::addFuncImport(const Sig& sig, uint32_t globalDataOffset) { MOZ_ASSERT(!finishedFuncDefs_); Sig copy; if (!copy.clone(sig)) return false; return metadata_->funcImports.emplaceBack(Move(copy), globalDataOffset); }
bool ModuleGenerator::declareExport(uint32_t funcIndex, uint32_t* exportIndex) { FuncIndexMap::AddPtr p = funcIndexToExport_.lookupForAdd(funcIndex); if (p) { *exportIndex = p->value(); return true; } Sig copy; if (!copy.clone(funcSig(funcIndex))) return false; *exportIndex = module_->exports.length(); return funcIndexToExport_.add(p, funcIndex, *exportIndex) && module_->exports.append(Move(copy)) && exportFuncIndices_.append(funcIndex); }
bool ModuleGenerator::finishFuncExports() { // In addition to all the functions that were explicitly exported, any // element of an exported table is also exported. for (ElemSegment& elems : elemSegments_) { if (shared_->tables[elems.tableIndex].external) { for (uint32_t funcIndex : elems.elemFuncIndices) { if (!exportedFuncs_.put(funcIndex)) return false; } } } // ModuleGenerator::exportedFuncs_ is an unordered HashSet. The // FuncExportVector stored in Metadata needs to be stored sorted by // function index to allow O(log(n)) lookup at runtime. Uint32Vector sorted; if (!sorted.reserve(exportedFuncs_.count())) return false; for (Uint32Set::Range r = exportedFuncs_.all(); !r.empty(); r.popFront()) sorted.infallibleAppend(r.front()); std::sort(sorted.begin(), sorted.end()); MOZ_ASSERT(metadata_->funcExports.empty()); if (!metadata_->funcExports.reserve(sorted.length())) return false; for (uint32_t funcIndex : sorted) { Sig sig; if (!sig.clone(funcSig(funcIndex))) return false; uint32_t codeRangeIndex = funcToCodeRange_[funcIndex]; metadata_->funcExports.infallibleEmplaceBack(Move(sig), funcIndex, codeRangeIndex); } return true; }
bool ModuleGenerator::init(UniqueModuleGeneratorData shared, const CompileArgs& args, Metadata* maybeAsmJSMetadata) { shared_ = Move(shared); alwaysBaseline_ = args.alwaysBaseline; if (!exportedFuncs_.init()) return false; linkData_.globalDataLength = AlignBytes(InitialGlobalDataBytes, sizeof(void*));; // asm.js passes in an AsmJSMetadata subclass to use instead. if (maybeAsmJSMetadata) { metadata_ = maybeAsmJSMetadata; MOZ_ASSERT(isAsmJS()); } else { metadata_ = js_new<Metadata>(); if (!metadata_) return false; MOZ_ASSERT(!isAsmJS()); } if (args.scriptedCaller.filename) { metadata_->filename = DuplicateString(args.scriptedCaller.filename.get()); if (!metadata_->filename) return false; } if (!metadata_->assumptions.clone(args.assumptions)) return false; // For asm.js, the Vectors in ModuleGeneratorData are max-sized reservations // and will be initialized in a linear order via init* functions as the // module is generated. For wasm, the Vectors are correctly-sized and // already initialized. if (!isAsmJS()) { numSigs_ = shared_->sigs.length(); numTables_ = shared_->tables.length(); for (FuncImportGenDesc& funcImport : shared_->funcImports) { MOZ_ASSERT(!funcImport.globalDataOffset); funcImport.globalDataOffset = linkData_.globalDataLength; linkData_.globalDataLength += sizeof(FuncImportTls); if (!addFuncImport(*funcImport.sig, funcImport.globalDataOffset)) return false; } for (const Import& import : imports_) { if (import.kind == DefinitionKind::Table) { MOZ_ASSERT(shared_->tables.length() == 1); shared_->tables[0].external = true; break; } } for (TableDesc& table : shared_->tables) { if (!allocateGlobalBytes(sizeof(void*), sizeof(void*), &table.globalDataOffset)) return false; } for (uint32_t i = 0; i < numSigs_; i++) { SigWithId& sig = shared_->sigs[i]; if (SigIdDesc::isGlobal(sig)) { uint32_t globalDataOffset; if (!allocateGlobalBytes(sizeof(void*), sizeof(void*), &globalDataOffset)) return false; sig.id = SigIdDesc::global(sig, globalDataOffset); Sig copy; if (!copy.clone(sig)) return false; if (!metadata_->sigIds.emplaceBack(Move(copy), sig.id)) return false; } else { sig.id = SigIdDesc::immediate(sig); } } for (GlobalDesc& global : shared_->globals) { if (global.isConstant()) continue; if (!allocateGlobal(&global)) return false; } } else { MOZ_ASSERT(shared_->sigs.length() == MaxSigs); MOZ_ASSERT(shared_->tables.length() == MaxTables); MOZ_ASSERT(shared_->asmJSSigToTableIndex.length() == MaxSigs); } return true; }