// Create a function type for the given params and result
ValTypeVector paramVec; if (!paramVec.append(params.data(), params.data() + params.size())) { returnfalse;
}
ValTypeVector resultVec; if (result.isSome() && !resultVec.append(*result)) { returnfalse;
} constTypeDef* typeDef =
types->addType(FuncType(std::move(paramVec), std::move(resultVec))); if (!typeDef) { returnfalse;
}
recGroup_ = &typeDef->recGroup(); returntrue;
}
bool EncodeFuncBody(const BuiltinModuleFunc& builtinModuleFunc,
BuiltinModuleFuncId id, Bytes* body) {
Encoder encoder(*body); if (!EncodeLocalEntries(encoder, ValTypeVector())) { returnfalse;
} const FuncType* funcType = builtinModuleFunc.funcType(); for (uint32_t i = 0; i < funcType->args().length(); i++) { if (!encoder.writeOp(Op::LocalGet) || !encoder.writeVarU32(i)) { returnfalse;
}
} if (!encoder.writeOp(MozOp::CallBuiltinModuleFunc)) { returnfalse;
} if (!encoder.writeVarU32(uint32_t(id))) { returnfalse;
} return encoder.writeOp(Op::End);
}
// Descriptor of how a builtin should use memory. struct BuiltinMemory { // Whether the memory is shared or not.
Shareable shared; // Optional import name for the memory. If not provided, will fall back to // "" "memory" as the import name. const Import* import;
if (memory.isSome()) { // Add (import (memory 0)) using the specified import name, or else fall // back to "" "memory" if no import was specified.
CacheableName moduleString;
CacheableName fieldString; if (!memory->import) { // Keep moduleString empty, using "memory" for the fieldString if (!CacheableName::fromUTF8Chars("memory", &fieldString)) {
ReportOutOfMemory(cx); returnfalse;
}
} else { // The provided import name must be a memory import.
MOZ_ASSERT(memory->import->kind == DefinitionKind::Memory); if (!memory->import->module.clone(&moduleString) ||
!memory->import->field.clone(&fieldString)) {
ReportOutOfMemory(cx); returnfalse;
}
}
if (!moduleMeta->imports.append(Import(std::move(moduleString),
std::move(fieldString),
DefinitionKind::Memory))) {
ReportOutOfMemory(cx); returnfalse;
} if (!codeMeta->memories.append(MemoryDesc(
Limits(0, Nothing(), memory->shared, PageSize::Standard)))) {
ReportOutOfMemory(cx); returnfalse;
}
}
// Add (type (func (params ...))) for each func. The function types will // be deduplicated by the runtime. for (uint32_t funcIndex = 0; funcIndex < ids.size(); funcIndex++) { const BuiltinModuleFuncId& id = ids[funcIndex]; const BuiltinModuleFunc& builtinModuleFunc =
BuiltinModuleFuncs::getFromId(id);
// Add all static type defs to the type context so that we can always look up // their index. This must come after the func types so as not to interfere // with funcIndex. if (!StaticTypeDefs::addAllToTypeContext(codeMeta->types)) {
ReportOutOfMemory(cx); returnfalse;
}
// Add (func (type $i)) declarations. Do this after all types have been added // as the function declaration metadata uses pointers into the type vectors // that must be stable. for (uint32_t funcIndex = 0; funcIndex < ids.size(); funcIndex++) {
FuncDesc decl(funcIndex); if (!codeMeta->funcs.append(decl)) {
ReportOutOfMemory(cx); returnfalse;
}
codeMeta->funcs[funcIndex].declareFuncExported(/* eager */ true, /* canRefFunc */ true);
}
if (!moduleMeta->prepareForCompile(compilerEnv.mode())) { returnfalse;
}
// Compile the module functions
UniqueChars error;
ModuleGenerator mg(*codeMeta, compilerEnv, compilerEnv.initialState(),
nullptr, &error, nullptr); if (!mg.initializeCompleteTier()) {
ReportOutOfMemory(cx); returnfalse;
}
// Prepare and compile function bodies
Vector<Bytes, 1, SystemAllocPolicy> bodies; if (!bodies.reserve(ids.size())) {
ReportOutOfMemory(cx); returnfalse;
}
uint32_t funcBytecodeOffset = CallSite::FIRST_VALID_BYTECODE_OFFSET; for (uint32_t funcIndex = 0; funcIndex < ids.size(); funcIndex++) {
BuiltinModuleFuncId id = ids[funcIndex]; const BuiltinModuleFunc& builtinModuleFunc =
BuiltinModuleFuncs::getFromId(ids[funcIndex]);
// Compilation may be done using other threads, ModuleGenerator requires // that function bodies live until after finishFuncDefs().
bodies.infallibleAppend(Bytes());
Bytes& bytecode = bodies.back();
// Encode function body that will call the builtinModuleFunc using our // builtin opcode, and launch a compile task if (!EncodeFuncBody(builtinModuleFunc, id, &bytecode) ||
!mg.compileFuncDef(funcIndex, funcBytecodeOffset, bytecode.begin(),
bytecode.begin() + bytecode.length())) { // This must be an OOM and will be reported by the caller
MOZ_ASSERT(!error);
ReportOutOfMemory(cx); returnfalse;
}
funcBytecodeOffset += bytecode.length();
}
// Finish and block on function compilation if (!mg.finishFuncDefs()) { // This must be an OOM and will be reported by the caller
MOZ_ASSERT(!error);
ReportOutOfMemory(cx); returnfalse;
}
// Finish the module
SharedModule module = mg.finishModule(BytecodeBufferOrSource(), *moduleMeta, /*maybeCompleteTier2Listener=*/nullptr); if (!module) {
ReportOutOfMemory(cx); returnfalse;
}
// Create a WasmModuleObject for the module, and return it
RootedObject proto(
cx, GlobalObject::getOrCreatePrototype(cx, JSProto_WasmModule)); if (!proto) {
ReportOutOfMemory(cx); returnfalse;
}
result.set(WasmModuleObject::create(cx, *module, proto)); return !!result;
}
bool wasm::ImportFieldMatchesBuiltinModuleDefinition(
mozilla::Span<constchar> importName, BuiltinModuleId module,
DefinitionKind kind, const BuiltinModuleFunc** matchedFunc,
BuiltinModuleFuncId* matchedFuncId) { if (kind != DefinitionKind::Function) { // JSStringConstants accepts all global imports; other builtin modules only // define functions. return module == BuiltinModuleId::JSStringConstants &&
kind == DefinitionKind::Global;
}
// Imported string constants don't define any functions if (module == BuiltinModuleId::JSStringConstants) { returnfalse;
}
#ifdef ENABLE_WASM_MOZ_INTGEMM if (module == BuiltinModuleId::IntGemm) { for (BuiltinModuleFuncId funcId : IntGemmFuncs) { const BuiltinModuleFunc& func = BuiltinModuleFuncs::getFromId(funcId); if (importName == mozilla::MakeStringSpan(func.exportName())) { if (matchedFunc) {
*matchedFunc = &func;
} if (matchedFuncId) {
*matchedFuncId = funcId;
} returntrue;
}
} returnfalse;
} #endif
// That leaves only the wasm:js-string module that defines functions at this // point, and is supported by implicit instantiation.
MOZ_RELEASE_ASSERT(module == BuiltinModuleId::JSString); for (BuiltinModuleFuncId funcId : JSStringFuncs) { const BuiltinModuleFunc& func = BuiltinModuleFuncs::getFromId(funcId); if (importName == mozilla::MakeStringSpan(func.exportName())) { if (matchedFunc) {
*matchedFunc = &func;
} if (matchedFuncId) {
*matchedFuncId = funcId;
} returntrue;
}
} returnfalse;
}
bool wasm::CompileBuiltinModule(JSContext* cx, BuiltinModuleId module, const Import* moduleMemoryImport,
MutableHandle<WasmModuleObject*> result) { // NOTE(bvisness): If you update the memory descriptors here, pay attention to // CheckBuiltinImportsHaveMemory in WasmValidate.cpp. switch (module) { case BuiltinModuleId::SelfTest: return CompileBuiltinModule(
cx, SelfTestFuncs, Some(BuiltinMemory(Shareable::False, nullptr)),
result); #ifdef ENABLE_WASM_MOZ_INTGEMM case BuiltinModuleId::IntGemm: return CompileBuiltinModule(
cx, IntGemmFuncs,
Some(BuiltinMemory(Shareable::False, moduleMemoryImport)), result); #endif// ENABLE_WASM_MOZ_INTGEMM case BuiltinModuleId::JSString: return CompileBuiltinModule(cx, JSStringFuncs, Nothing(), result); case BuiltinModuleId::JSStringConstants:
MOZ_CRASH(); default:
MOZ_CRASH();
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.