зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1284155 - Baldr: consolidate instantiation code in Module::instantiate (r=bbouvier)
MozReview-Commit-ID: xFc5PQIbJ5 --HG-- extra : rebase_source : b45bc377dbd44106de74c257714e483cc36e5622
This commit is contained in:
Родитель
1aca4ab5d1
Коммит
9133d68cc4
|
@ -26,15 +26,14 @@
|
|||
#include "asmjs/WasmJS.h"
|
||||
#include "asmjs/WasmModule.h"
|
||||
#include "builtin/SIMD.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/JitCommon.h"
|
||||
#include "jit/JitOptions.h"
|
||||
#include "jit/JitCompartment.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/ArrayBufferObject-inl.h"
|
||||
#include "vm/Debugger-inl.h"
|
||||
#include "vm/TypeInference-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
@ -346,171 +345,30 @@ Instance::callImport_f64(int32_t funcImportIndex, int32_t argc, uint64_t* argv)
|
|||
return ToNumber(cx, rval, (double*)argv);
|
||||
}
|
||||
|
||||
static bool
|
||||
WasmCall(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedFunction callee(cx, &args.callee().as<JSFunction>());
|
||||
|
||||
Instance& instance = ExportedFunctionToInstance(callee);
|
||||
uint32_t exportIndex = ExportedFunctionToExportIndex(callee);
|
||||
|
||||
return instance.callExport(cx, exportIndex, args);
|
||||
}
|
||||
|
||||
static JSFunction*
|
||||
NewExportedFunction(JSContext* cx, Handle<WasmInstanceObject*> instanceObj, uint32_t exportIndex)
|
||||
{
|
||||
Instance& instance = instanceObj->instance();
|
||||
const Metadata& metadata = instance.metadata();
|
||||
const Export& exp = metadata.exports[exportIndex];
|
||||
unsigned numArgs = exp.sig().args().length();
|
||||
|
||||
RootedAtom name(cx, instance.getFuncAtom(cx, exp.funcIndex()));
|
||||
if (!name)
|
||||
return nullptr;
|
||||
|
||||
JSFunction* fun = NewNativeConstructor(cx, WasmCall, numArgs, name,
|
||||
gc::AllocKind::FUNCTION_EXTENDED, GenericObject,
|
||||
JSFunction::ASMJS_CTOR);
|
||||
if (!fun)
|
||||
return nullptr;
|
||||
|
||||
fun->setExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT, ObjectValue(*instanceObj));
|
||||
fun->setExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT, Int32Value(exportIndex));
|
||||
return fun;
|
||||
}
|
||||
|
||||
static bool
|
||||
CreateExportObject(JSContext* cx,
|
||||
HandleWasmInstanceObject instanceObj,
|
||||
HandleWasmMemoryObject memoryObj,
|
||||
const ExportMap& exportMap,
|
||||
const Metadata& metadata,
|
||||
MutableHandleObject exportObj)
|
||||
{
|
||||
MOZ_ASSERT(exportMap.fieldNames.length() == exportMap.fieldsToExports.length());
|
||||
|
||||
if (metadata.isAsmJS() &&
|
||||
exportMap.fieldNames.length() == 1 &&
|
||||
strlen(exportMap.fieldNames[0].get()) == 0)
|
||||
{
|
||||
exportObj.set(NewExportedFunction(cx, instanceObj, 0));
|
||||
return !!exportObj;
|
||||
}
|
||||
|
||||
exportObj.set(JS_NewPlainObject(cx));
|
||||
if (!exportObj)
|
||||
return false;
|
||||
|
||||
Rooted<ValueVector> vals(cx, ValueVector(cx));
|
||||
for (size_t exportIndex = 0; exportIndex < metadata.exports.length(); exportIndex++) {
|
||||
JSFunction* fun = NewExportedFunction(cx, instanceObj, exportIndex);
|
||||
if (!fun || !vals.append(ObjectValue(*fun)))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t fieldIndex = 0; fieldIndex < exportMap.fieldNames.length(); fieldIndex++) {
|
||||
const char* fieldName = exportMap.fieldNames[fieldIndex].get();
|
||||
JSAtom* atom = AtomizeUTF8Chars(cx, fieldName, strlen(fieldName));
|
||||
if (!atom)
|
||||
return false;
|
||||
|
||||
RootedId id(cx, AtomToId(atom));
|
||||
RootedValue val(cx);
|
||||
uint32_t exportIndex = exportMap.fieldsToExports[fieldIndex];
|
||||
if (exportIndex == MemoryExport) {
|
||||
if (metadata.assumptions.newFormat)
|
||||
val = ObjectValue(*memoryObj);
|
||||
else
|
||||
val = ObjectValue(memoryObj->buffer());
|
||||
} else {
|
||||
val = vals[exportIndex];
|
||||
}
|
||||
|
||||
if (!JS_DefinePropertyById(cx, exportObj, id, val, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Instance::Instance(UniqueCodeSegment codeSegment,
|
||||
const Metadata& metadata,
|
||||
const ShareableBytes* maybeBytecode,
|
||||
TypedFuncTableVector&& typedFuncTables,
|
||||
HandleWasmMemoryObject memory)
|
||||
HandleWasmMemoryObject memory,
|
||||
Handle<FunctionVector> funcImports)
|
||||
: codeSegment_(Move(codeSegment)),
|
||||
metadata_(&metadata),
|
||||
maybeBytecode_(maybeBytecode),
|
||||
typedFuncTables_(Move(typedFuncTables)),
|
||||
memory_(memory),
|
||||
profilingEnabled_(false)
|
||||
{}
|
||||
|
||||
static const char ExportField[] = "exports";
|
||||
|
||||
/* static */ bool
|
||||
Instance::create(JSContext* cx,
|
||||
UniqueCodeSegment codeSegment,
|
||||
const Metadata& metadata,
|
||||
const ShareableBytes* maybeBytecode,
|
||||
TypedFuncTableVector&& typedFuncTables,
|
||||
HandleWasmMemoryObject memory,
|
||||
Handle<FunctionVector> funcImports,
|
||||
const ExportMap& exportMap,
|
||||
HandleWasmInstanceObject instanceObj)
|
||||
{
|
||||
// Ensure that the Instance is traceable via 'instanceObj' before any GC.
|
||||
|
||||
{
|
||||
auto instance = cx->make_unique<Instance>(Move(codeSegment), metadata, maybeBytecode,
|
||||
Move(typedFuncTables), memory);
|
||||
if (!instance)
|
||||
return false;
|
||||
|
||||
instanceObj->init(Move(instance));
|
||||
}
|
||||
|
||||
// Initialize the instance.
|
||||
|
||||
Instance& instance = instanceObj->instance();
|
||||
|
||||
MOZ_ASSERT(funcImports.length() == metadata.funcImports.length());
|
||||
for (size_t i = 0; i < metadata.funcImports.length(); i++) {
|
||||
const FuncImport& fi = metadata.funcImports[i];
|
||||
FuncImportExit& exit = instance.funcImportToExit(fi);
|
||||
exit.code = instance.codeSegment().code() + fi.interpExitCodeOffset();
|
||||
FuncImportExit& exit = funcImportToExit(fi);
|
||||
exit.code = codeSegment_->code() + fi.interpExitCodeOffset();
|
||||
exit.fun = funcImports[i];
|
||||
exit.baselineScript = nullptr;
|
||||
}
|
||||
|
||||
if (memory)
|
||||
*instance.addressOfMemoryBase() = memory->buffer().dataPointerEither().unwrap();
|
||||
|
||||
// Create the export object.
|
||||
|
||||
RootedObject exportObj(cx);
|
||||
if (!CreateExportObject(cx, instanceObj, memory, exportMap, metadata, &exportObj))
|
||||
return false;
|
||||
|
||||
// Attach the export object to the instance object.
|
||||
|
||||
instanceObj->initExportsObject(exportObj);
|
||||
|
||||
JSAtom* atom = Atomize(cx, ExportField, strlen(ExportField));
|
||||
if (!atom)
|
||||
return false;
|
||||
RootedId id(cx, AtomToId(atom));
|
||||
|
||||
RootedValue val(cx, ObjectValue(*exportObj));
|
||||
if (!JS_DefinePropertyById(cx, instanceObj, id, val, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
|
||||
// Notify the Debugger of the new Instance.
|
||||
|
||||
Debugger::onNewWasmInstance(cx, instanceObj);
|
||||
|
||||
return true;
|
||||
*addressOfMemoryBase() = memory->buffer().dataPointerEither().unwrap();
|
||||
}
|
||||
|
||||
Instance::~Instance()
|
||||
|
@ -878,25 +736,3 @@ Instance::addSizeOfMisc(MallocSizeOf mallocSizeOf,
|
|||
if (maybeBytecode_)
|
||||
*data += maybeBytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
|
||||
}
|
||||
|
||||
bool
|
||||
wasm::IsExportedFunction(JSFunction* fun)
|
||||
{
|
||||
return fun->maybeNative() == WasmCall;
|
||||
}
|
||||
|
||||
Instance&
|
||||
wasm::ExportedFunctionToInstance(JSFunction* fun)
|
||||
{
|
||||
MOZ_ASSERT(IsExportedFunction(fun));
|
||||
const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT);
|
||||
return v.toObject().as<WasmInstanceObject>().instance();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasm::ExportedFunctionToExportIndex(JSFunction* fun)
|
||||
{
|
||||
MOZ_ASSERT(IsExportedFunction(fun));
|
||||
const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT);
|
||||
return v.toInt32();
|
||||
}
|
||||
|
|
|
@ -84,23 +84,13 @@ class Instance
|
|||
static int32_t callImport_i64(int32_t importIndex, int32_t argc, uint64_t* argv);
|
||||
static int32_t callImport_f64(int32_t importIndex, int32_t argc, uint64_t* argv);
|
||||
|
||||
template <class T> friend struct js::MallocProvider;
|
||||
public:
|
||||
Instance(UniqueCodeSegment codeSegment,
|
||||
const Metadata& metadata,
|
||||
const ShareableBytes* maybeBytecode,
|
||||
TypedFuncTableVector&& typedFuncTables,
|
||||
HandleWasmMemoryObject memory);
|
||||
|
||||
public:
|
||||
static bool create(JSContext* cx,
|
||||
UniqueCodeSegment codeSegment,
|
||||
const Metadata& metadata,
|
||||
const ShareableBytes* maybeBytecode,
|
||||
TypedFuncTableVector&& typedFuncTables,
|
||||
HandleWasmMemoryObject memoryObject,
|
||||
Handle<FunctionVector> funcImports,
|
||||
const ExportMap& exports,
|
||||
HandleWasmInstanceObject instanceObj);
|
||||
HandleWasmMemoryObject memory,
|
||||
Handle<FunctionVector> funcImports);
|
||||
~Instance();
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
|
@ -162,18 +152,6 @@ class Instance
|
|||
|
||||
typedef UniquePtr<Instance> UniqueInstance;
|
||||
|
||||
// These accessors are used to implemented the special asm.js semantics of
|
||||
// exported wasm functions:
|
||||
|
||||
extern bool
|
||||
IsExportedFunction(JSFunction* fun);
|
||||
|
||||
extern Instance&
|
||||
ExportedFunctionToInstance(JSFunction* fun);
|
||||
|
||||
extern uint32_t
|
||||
ExportedFunctionToExportIndex(JSFunction* fun);
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "asmjs/WasmSerialize.h"
|
||||
|
||||
#include "vm/ArrayBufferObject-inl.h"
|
||||
#include "vm/Debugger-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::wasm;
|
||||
|
@ -376,6 +377,97 @@ Module::instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) c
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
WasmCall(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedFunction callee(cx, &args.callee().as<JSFunction>());
|
||||
|
||||
Instance& instance = ExportedFunctionToInstance(callee);
|
||||
uint32_t exportIndex = ExportedFunctionToExportIndex(callee);
|
||||
|
||||
return instance.callExport(cx, exportIndex, args);
|
||||
}
|
||||
|
||||
static JSFunction*
|
||||
NewExportedFunction(JSContext* cx, Handle<WasmInstanceObject*> instanceObj, uint32_t exportIndex)
|
||||
{
|
||||
Instance& instance = instanceObj->instance();
|
||||
const Metadata& metadata = instance.metadata();
|
||||
const Export& exp = metadata.exports[exportIndex];
|
||||
unsigned numArgs = exp.sig().args().length();
|
||||
|
||||
RootedAtom name(cx, instance.getFuncAtom(cx, exp.funcIndex()));
|
||||
if (!name)
|
||||
return nullptr;
|
||||
|
||||
JSFunction* fun = NewNativeConstructor(cx, WasmCall, numArgs, name,
|
||||
gc::AllocKind::FUNCTION_EXTENDED, GenericObject,
|
||||
JSFunction::ASMJS_CTOR);
|
||||
if (!fun)
|
||||
return nullptr;
|
||||
|
||||
fun->setExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT, ObjectValue(*instanceObj));
|
||||
fun->setExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT, Int32Value(exportIndex));
|
||||
return fun;
|
||||
}
|
||||
|
||||
static bool
|
||||
CreateExportObject(JSContext* cx,
|
||||
HandleWasmInstanceObject instanceObj,
|
||||
HandleWasmMemoryObject memoryObj,
|
||||
const ExportMap& exportMap,
|
||||
const Metadata& metadata,
|
||||
MutableHandleObject exportObj)
|
||||
{
|
||||
MOZ_ASSERT(exportMap.fieldNames.length() == exportMap.fieldsToExports.length());
|
||||
|
||||
if (metadata.isAsmJS() &&
|
||||
exportMap.fieldNames.length() == 1 &&
|
||||
strlen(exportMap.fieldNames[0].get()) == 0)
|
||||
{
|
||||
exportObj.set(NewExportedFunction(cx, instanceObj, 0));
|
||||
return !!exportObj;
|
||||
}
|
||||
|
||||
exportObj.set(JS_NewPlainObject(cx));
|
||||
if (!exportObj)
|
||||
return false;
|
||||
|
||||
Rooted<ValueVector> vals(cx, ValueVector(cx));
|
||||
for (size_t exportIndex = 0; exportIndex < metadata.exports.length(); exportIndex++) {
|
||||
JSFunction* fun = NewExportedFunction(cx, instanceObj, exportIndex);
|
||||
if (!fun || !vals.append(ObjectValue(*fun)))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t fieldIndex = 0; fieldIndex < exportMap.fieldNames.length(); fieldIndex++) {
|
||||
const char* fieldName = exportMap.fieldNames[fieldIndex].get();
|
||||
JSAtom* atom = AtomizeUTF8Chars(cx, fieldName, strlen(fieldName));
|
||||
if (!atom)
|
||||
return false;
|
||||
|
||||
RootedId id(cx, AtomToId(atom));
|
||||
RootedValue val(cx);
|
||||
uint32_t exportIndex = exportMap.fieldsToExports[fieldIndex];
|
||||
if (exportIndex == MemoryExport) {
|
||||
if (metadata.assumptions.newFormat)
|
||||
val = ObjectValue(*memoryObj);
|
||||
else
|
||||
val = ObjectValue(memoryObj->buffer());
|
||||
} else {
|
||||
val = vals[exportIndex];
|
||||
}
|
||||
|
||||
if (!JS_DefinePropertyById(cx, exportObj, id, val, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char ExportField[] = "exports";
|
||||
|
||||
bool
|
||||
Module::instantiate(JSContext* cx,
|
||||
Handle<FunctionVector> funcImports,
|
||||
|
@ -398,6 +490,7 @@ Module::instantiate(JSContext* cx,
|
|||
// developer actually cares: when the compartment is debuggable (which is
|
||||
// true when the web console is open) or a names section is implied (since
|
||||
// this going to be stripped for non-developer builds).
|
||||
|
||||
const ShareableBytes* maybeBytecode = nullptr;
|
||||
if (cx->compartment()->isDebuggee() || !metadata_->funcNames.empty())
|
||||
maybeBytecode = bytecode_.get();
|
||||
|
@ -405,6 +498,7 @@ Module::instantiate(JSContext* cx,
|
|||
// Store a summary of LinkData::FuncTableVector, only as much is needed
|
||||
// for runtime toggling of profiling mode. Currently, only asm.js has typed
|
||||
// function tables.
|
||||
|
||||
TypedFuncTableVector typedFuncTables;
|
||||
if (metadata_->isAsmJS()) {
|
||||
if (!typedFuncTables.reserve(linkData_.funcTables.length()))
|
||||
|
@ -413,6 +507,65 @@ Module::instantiate(JSContext* cx,
|
|||
typedFuncTables.infallibleEmplaceBack(tbl.globalDataOffset, tbl.elemOffsets.length());
|
||||
}
|
||||
|
||||
return Instance::create(cx, Move(cs), *metadata_, maybeBytecode, Move(typedFuncTables),
|
||||
memory, funcImports, exportMap_, instanceObj);
|
||||
// Create the Instance, ensuring that it is traceable via 'instanceObj'
|
||||
// before any GC can occur and invalidate the pointers stored in global
|
||||
// memory.
|
||||
|
||||
{
|
||||
auto instance = cx->make_unique<Instance>(Move(cs),
|
||||
*metadata_,
|
||||
maybeBytecode,
|
||||
Move(typedFuncTables),
|
||||
memory,
|
||||
funcImports);
|
||||
if (!instance)
|
||||
return false;
|
||||
|
||||
instanceObj->init(Move(instance));
|
||||
}
|
||||
|
||||
// Create the export object.
|
||||
|
||||
RootedObject exportObj(cx);
|
||||
if (!CreateExportObject(cx, instanceObj, memory, exportMap_, *metadata_, &exportObj))
|
||||
return false;
|
||||
|
||||
instanceObj->initExportsObject(exportObj);
|
||||
|
||||
JSAtom* atom = Atomize(cx, ExportField, strlen(ExportField));
|
||||
if (!atom)
|
||||
return false;
|
||||
RootedId id(cx, AtomToId(atom));
|
||||
|
||||
RootedValue val(cx, ObjectValue(*exportObj));
|
||||
if (!JS_DefinePropertyById(cx, instanceObj, id, val, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
|
||||
// Done! Notify the Debugger of the new Instance.
|
||||
|
||||
Debugger::onNewWasmInstance(cx, instanceObj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm::IsExportedFunction(JSFunction* fun)
|
||||
{
|
||||
return fun->maybeNative() == WasmCall;
|
||||
}
|
||||
|
||||
Instance&
|
||||
wasm::ExportedFunctionToInstance(JSFunction* fun)
|
||||
{
|
||||
MOZ_ASSERT(IsExportedFunction(fun));
|
||||
const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT);
|
||||
return v.toObject().as<WasmInstanceObject>().instance();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wasm::ExportedFunctionToExportIndex(JSFunction* fun)
|
||||
{
|
||||
MOZ_ASSERT(IsExportedFunction(fun));
|
||||
const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT);
|
||||
return v.toInt32();
|
||||
}
|
||||
|
|
|
@ -214,6 +214,18 @@ class Module
|
|||
|
||||
typedef UniquePtr<Module> UniqueModule;
|
||||
|
||||
// These accessors are used to implemented the special asm.js semantics of
|
||||
// exported wasm functions:
|
||||
|
||||
extern bool
|
||||
IsExportedFunction(JSFunction* fun);
|
||||
|
||||
extern Instance&
|
||||
ExportedFunctionToInstance(JSFunction* fun);
|
||||
|
||||
extern uint32_t
|
||||
ExportedFunctionToExportIndex(JSFunction* fun);
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче