зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1284155 - Baldr: add WebAssembly.Table constructor and object (r=bbouvier)
MozReview-Commit-ID: CtMsvJroBfK --HG-- extra : rebase_source : 18a935cafd520e24c4635c0e45932101e751f44a
This commit is contained in:
Родитель
9105b9d2ea
Коммит
1b4ff6fb6f
|
@ -292,8 +292,8 @@ WasmModuleObject::create(ExclusiveContext* cx, UniqueModule module, HandleObject
|
|||
return obj;
|
||||
}
|
||||
|
||||
static bool
|
||||
ModuleConstructor(JSContext* cx, unsigned argc, Value* vp)
|
||||
/* static */ bool
|
||||
WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs callArgs = CallArgsFromVp(argc, vp);
|
||||
|
||||
|
@ -441,8 +441,8 @@ WasmInstanceObject::initExportsObject(HandleObject exportObj)
|
|||
initReservedSlot(EXPORTS_SLOT, ObjectValue(*exportObj));
|
||||
}
|
||||
|
||||
static bool
|
||||
InstanceConstructor(JSContext* cx, unsigned argc, Value* vp)
|
||||
/* static */ bool
|
||||
WasmInstanceObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
|
@ -522,8 +522,8 @@ WasmMemoryObject::create(ExclusiveContext* cx, HandleArrayBufferObjectMaybeShare
|
|||
return obj;
|
||||
}
|
||||
|
||||
static bool
|
||||
MemoryConstructor(JSContext* cx, unsigned argc, Value* vp)
|
||||
/* static */ bool
|
||||
WasmMemoryObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
|
@ -534,7 +534,7 @@ MemoryConstructor(JSContext* cx, unsigned argc, Value* vp)
|
|||
return false;
|
||||
|
||||
if (!args.get(0).isObject()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_MEM_ARG);
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_DESC_ARG, "memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -553,7 +553,7 @@ MemoryConstructor(JSContext* cx, unsigned argc, Value* vp)
|
|||
return false;
|
||||
|
||||
if (initialDbl < 0 || initialDbl > INT32_MAX / PageSize) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_MEM_SIZE, "initial");
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_SIZE, "Memory", "initial");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -604,6 +604,105 @@ WasmMemoryObject::buffer() const
|
|||
return getReservedSlot(BUFFER_SLOT).toObject().as<ArrayBufferObjectMaybeShared>();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// WebAssembly.Table class and methods
|
||||
|
||||
static void
|
||||
WasmTableObject_finalize(FreeOp* fop, JSObject* obj)
|
||||
{
|
||||
obj->as<WasmTableObject>().table().Release();
|
||||
}
|
||||
|
||||
static const ClassOps WasmTableObject_classOps =
|
||||
{
|
||||
nullptr, /* addProperty */
|
||||
nullptr, /* delProperty */
|
||||
nullptr, /* getProperty */
|
||||
nullptr, /* setProperty */
|
||||
nullptr, /* enumerate */
|
||||
nullptr, /* resolve */
|
||||
nullptr, /* mayResolve */
|
||||
WasmTableObject_finalize
|
||||
};
|
||||
|
||||
const Class WasmTableObject::class_ =
|
||||
{
|
||||
"WebAssembly.Table",
|
||||
JSCLASS_DELAY_METADATA_BUILDER |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(WasmTableObject::RESERVED_SLOTS),
|
||||
&WasmTableObject_classOps
|
||||
};
|
||||
|
||||
const JSPropertySpec WasmTableObject::properties[] =
|
||||
{ JS_PS_END };
|
||||
|
||||
/* static */ WasmTableObject*
|
||||
WasmTableObject::create(ExclusiveContext* cx, Table& table, HandleObject proto)
|
||||
{
|
||||
AutoSetNewObjectMetadata metadata(cx);
|
||||
auto* obj = NewObjectWithGivenProto<WasmTableObject>(cx, proto);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
obj->initReservedSlot(TABLE_SLOT, PrivateValue((void*)&table));
|
||||
table.AddRef();
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
WasmTableObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (!ThrowIfNotConstructing(cx, args, "Table"))
|
||||
return false;
|
||||
|
||||
if (!args.requireAtLeast(cx, "WebAssembly.Table", 1))
|
||||
return false;
|
||||
|
||||
if (!args.get(0).isObject()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_DESC_ARG, "table");
|
||||
return false;
|
||||
}
|
||||
|
||||
JSAtom* initialAtom = Atomize(cx, "initial", strlen("initial"));
|
||||
if (!initialAtom)
|
||||
return false;
|
||||
|
||||
RootedObject obj(cx, &args[0].toObject());
|
||||
RootedId id(cx, AtomToId(initialAtom));
|
||||
RootedValue initialVal(cx);
|
||||
if (!GetProperty(cx, obj, obj, id, &initialVal))
|
||||
return false;
|
||||
|
||||
double initialDbl;
|
||||
if (!ToInteger(cx, initialVal, &initialDbl))
|
||||
return false;
|
||||
|
||||
if (initialDbl < 0 || initialDbl > INT32_MAX) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_SIZE, "Table", "initial");
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedTable table = Table::create(cx, TableKind::AnyFunction, uint32_t(initialDbl));
|
||||
if (!table)
|
||||
return false;
|
||||
|
||||
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmTable).toObject());
|
||||
RootedWasmTableObject tableObj(cx, WasmTableObject::create(cx, *table, proto));
|
||||
if (!tableObj)
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*tableObj);
|
||||
return true;
|
||||
}
|
||||
|
||||
Table&
|
||||
WasmTableObject::table() const
|
||||
{
|
||||
return *(Table*)getReservedSlot(TABLE_SLOT).toPrivate();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// WebAssembly class and static methods
|
||||
|
||||
|
@ -633,8 +732,7 @@ const Class js::WebAssemblyClass =
|
|||
|
||||
template <class Class>
|
||||
static bool
|
||||
InitConstructor(JSContext* cx, HandleObject global, HandleObject wasm, const char* name,
|
||||
Native native)
|
||||
InitConstructor(JSContext* cx, HandleObject global, HandleObject wasm, const char* name)
|
||||
{
|
||||
RootedObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx, SingletonObject));
|
||||
if (!proto)
|
||||
|
@ -647,7 +745,7 @@ InitConstructor(JSContext* cx, HandleObject global, HandleObject wasm, const cha
|
|||
if (!className)
|
||||
return false;
|
||||
|
||||
RootedFunction ctor(cx, NewNativeConstructor(cx, native, 1, className));
|
||||
RootedFunction ctor(cx, NewNativeConstructor(cx, Class::construct, 1, className));
|
||||
if (!ctor)
|
||||
return false;
|
||||
|
||||
|
@ -684,11 +782,13 @@ js::InitWebAssemblyClass(JSContext* cx, HandleObject global)
|
|||
if (!JS_DefineProperty(cx, wasm, "experimentalVersion", EncodingVersion, JSPROP_RESOLVING))
|
||||
return nullptr;
|
||||
|
||||
if (!InitConstructor<WasmModuleObject>(cx, global, wasm, "Module", ModuleConstructor))
|
||||
if (!InitConstructor<WasmModuleObject>(cx, global, wasm, "Module"))
|
||||
return nullptr;
|
||||
if (!InitConstructor<WasmInstanceObject>(cx, global, wasm, "Instance", InstanceConstructor))
|
||||
if (!InitConstructor<WasmInstanceObject>(cx, global, wasm, "Instance"))
|
||||
return nullptr;
|
||||
if (!InitConstructor<WasmMemoryObject>(cx, global, wasm, "Memory", MemoryConstructor))
|
||||
if (!InitConstructor<WasmMemoryObject>(cx, global, wasm, "Memory"))
|
||||
return nullptr;
|
||||
if (!InitConstructor<WasmTableObject>(cx, global, wasm, "Table"))
|
||||
return nullptr;
|
||||
|
||||
if (!JS_DefineFunctions(cx, wasm, WebAssembly_static_methods))
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace wasm {
|
|||
|
||||
class Module;
|
||||
class Instance;
|
||||
class Table;
|
||||
|
||||
typedef UniquePtr<Module> UniqueModule;
|
||||
typedef UniquePtr<Instance> UniqueInstance;
|
||||
|
@ -82,6 +83,7 @@ class WasmModuleObject : public NativeObject
|
|||
static const unsigned RESERVED_SLOTS = 1;
|
||||
static const Class class_;
|
||||
static const JSPropertySpec properties[];
|
||||
static bool construct(JSContext*, unsigned, Value*);
|
||||
|
||||
static WasmModuleObject* create(ExclusiveContext* cx,
|
||||
wasm::UniqueModule module,
|
||||
|
@ -110,6 +112,7 @@ class WasmInstanceObject : public NativeObject
|
|||
static const unsigned RESERVED_SLOTS = 2;
|
||||
static const Class class_;
|
||||
static const JSPropertySpec properties[];
|
||||
static bool construct(JSContext*, unsigned, Value*);
|
||||
|
||||
static WasmInstanceObject* create(ExclusiveContext* cx,
|
||||
HandleObject proto = nullptr);
|
||||
|
@ -136,6 +139,7 @@ class WasmMemoryObject : public NativeObject
|
|||
static const unsigned RESERVED_SLOTS = 1;
|
||||
static const Class class_;
|
||||
static const JSPropertySpec properties[];
|
||||
static bool construct(JSContext*, unsigned, Value*);
|
||||
|
||||
static WasmMemoryObject* create(ExclusiveContext* cx,
|
||||
Handle<ArrayBufferObjectMaybeShared*> buffer,
|
||||
|
@ -148,6 +152,29 @@ typedef Rooted<WasmMemoryObject*> RootedWasmMemoryObject;
|
|||
typedef Handle<WasmMemoryObject*> HandleWasmMemoryObject;
|
||||
typedef MutableHandle<WasmMemoryObject*> MutableHandleWasmMemoryObject;
|
||||
|
||||
// The class of WebAssembly.Table. A WasmTableObject holds a refcount on a
|
||||
// wasm::Table, allowing a Table to be shared between multiple Instances
|
||||
// (eventually between multiple threads).
|
||||
|
||||
class WasmTableObject : public NativeObject
|
||||
{
|
||||
static const unsigned TABLE_SLOT = 0;
|
||||
public:
|
||||
static const JSProtoKey KEY = JSProto_WasmTable;
|
||||
static const unsigned RESERVED_SLOTS = 1;
|
||||
static const Class class_;
|
||||
static const JSPropertySpec properties[];
|
||||
static bool construct(JSContext*, unsigned, Value*);
|
||||
|
||||
static WasmTableObject* create(ExclusiveContext* cx,
|
||||
wasm::Table& table,
|
||||
HandleObject proto);
|
||||
wasm::Table& table() const;
|
||||
};
|
||||
|
||||
typedef Rooted<WasmTableObject*> RootedWasmTableObject;
|
||||
typedef Handle<WasmTableObject*> HandleWasmTableObject;
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // wasm_js_h
|
||||
|
|
|
@ -4,6 +4,7 @@ load(libdir + 'asserts.js');
|
|||
const Module = WebAssembly.Module;
|
||||
const Instance = WebAssembly.Instance;
|
||||
const Memory = WebAssembly.Memory;
|
||||
const Table = WebAssembly.Table;
|
||||
|
||||
const mem1Page = new Memory({initial:1});
|
||||
const mem2Page = new Memory({initial:2});
|
||||
|
|
|
@ -121,8 +121,8 @@ assertErrorMessage(() => new Memory(1), TypeError, "first argument must be a mem
|
|||
assertErrorMessage(() => new Memory({initial:{valueOf() { throw new Error("here")}}}), Error, "here");
|
||||
assertErrorMessage(() => new Memory({initial:-1}), TypeError, /bad Memory initial size/);
|
||||
assertErrorMessage(() => new Memory({initial:Math.pow(2,32)}), TypeError, /bad Memory initial size/);
|
||||
assertErrorMessage(() => new Memory({initial:Math.pow(2,32)}), TypeError, /bad Memory initial size/);
|
||||
assertEq(new Memory({initial:1}) instanceof Memory, true);
|
||||
assertEq(new Memory({initial:1.5}).buffer.byteLength, 64*1024);
|
||||
|
||||
// 'WebAssembly.Memory.prototype' property
|
||||
const memoryProtoDesc = Object.getOwnPropertyDescriptor(Memory, 'prototype');
|
||||
|
@ -157,3 +157,41 @@ assertErrorMessage(() => bufferGetter.call({}), TypeError, /called on incompatib
|
|||
assertEq(bufferGetter.call(mem1) instanceof ArrayBuffer, true);
|
||||
assertEq(bufferGetter.call(mem1).byteLength, 64 * 1024);
|
||||
|
||||
// 'WebAssembly.Table' property
|
||||
const tableDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Table');
|
||||
assertEq(typeof tableDesc.value, "function");
|
||||
assertEq(tableDesc.writable, true);
|
||||
assertEq(tableDesc.enumerable, false);
|
||||
assertEq(tableDesc.configurable, true);
|
||||
|
||||
// 'WebAssembly.Table' constructor function
|
||||
const Table = WebAssembly.Table;
|
||||
assertEq(Table, tableDesc.value);
|
||||
assertEq(Table.length, 1);
|
||||
assertEq(Table.name, "Table");
|
||||
assertErrorMessage(() => Table(), TypeError, /constructor without new is forbidden/);
|
||||
assertErrorMessage(() => new Table(1), TypeError, "first argument must be a table descriptor");
|
||||
assertErrorMessage(() => new Table({initial:{valueOf() { throw new Error("here")}}}), Error, "here");
|
||||
assertErrorMessage(() => new Table({initial:-1}), TypeError, /bad Table initial size/);
|
||||
assertErrorMessage(() => new Table({initial:Math.pow(2,32)}), TypeError, /bad Table initial size/);
|
||||
assertEq(new Table({initial:1}) instanceof Table, true);
|
||||
assertEq(new Table({initial:1.5}) instanceof Table, true);
|
||||
|
||||
// 'WebAssembly.Table.prototype' property
|
||||
const tableProtoDesc = Object.getOwnPropertyDescriptor(Table, 'prototype');
|
||||
assertEq(typeof tableProtoDesc.value, "object");
|
||||
assertEq(tableProtoDesc.writable, false);
|
||||
assertEq(tableProtoDesc.enumerable, false);
|
||||
assertEq(tableProtoDesc.configurable, false);
|
||||
|
||||
// 'WebAssembly.Table.prototype' object
|
||||
const tableProto = Table.prototype;
|
||||
assertEq(tableProto, tableProtoDesc.value);
|
||||
assertEq(String(tableProto), "[object Object]");
|
||||
assertEq(Object.getPrototypeOf(tableProto), Object.prototype);
|
||||
|
||||
// 'WebAssembly.Table' instance objects
|
||||
const tbl1 = new Table({initial:1});
|
||||
assertEq(typeof tbl1, "object");
|
||||
assertEq(String(tbl1), "[object WebAssembly.Table]");
|
||||
assertEq(Object.getPrototypeOf(tbl1), tableProto);
|
||||
|
|
|
@ -347,9 +347,9 @@ MSG_DEF(JSMSG_WASM_TEXT_FAIL, 1, JSEXN_SYNTAXERR, "wasm text error: {
|
|||
MSG_DEF(JSMSG_WASM_BAD_IND_CALL, 0, JSEXN_ERR, "bad wasm indirect call")
|
||||
MSG_DEF(JSMSG_WASM_BAD_BUF_ARG, 0, JSEXN_TYPEERR, "first argument must be an ArrayBuffer or typed array object")
|
||||
MSG_DEF(JSMSG_WASM_BAD_MOD_ARG, 0, JSEXN_TYPEERR, "first argument must be a WebAssembly.Module")
|
||||
MSG_DEF(JSMSG_WASM_BAD_MEM_ARG, 0, JSEXN_TYPEERR, "first argument must be a memory descriptor")
|
||||
MSG_DEF(JSMSG_WASM_BAD_DESC_ARG, 1, JSEXN_TYPEERR, "first argument must be a {0} descriptor")
|
||||
MSG_DEF(JSMSG_WASM_BAD_MEM_IMP_SIZE, 0, JSEXN_TYPEERR, "imported Memory with incompatible size")
|
||||
MSG_DEF(JSMSG_WASM_BAD_MEM_SIZE, 1, JSEXN_TYPEERR, "bad Memory {0} size")
|
||||
MSG_DEF(JSMSG_WASM_BAD_SIZE, 2, JSEXN_TYPEERR, "bad {0} {1} size")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument, if present, must be an object")
|
||||
MSG_DEF(JSMSG_WASM_UNREACHABLE, 0, JSEXN_ERR, "unreachable executed")
|
||||
MSG_DEF(JSMSG_WASM_INTEGER_OVERFLOW, 0, JSEXN_ERR, "integer overflow")
|
||||
|
|
|
@ -120,7 +120,8 @@ IF_SAB(real,imaginary)(Atomics, 45, InitAtomicsClass, OCLASP(Atomics)) \
|
|||
imaginary(WasmModule, 49, dummy, dummy) \
|
||||
imaginary(WasmInstance, 50, dummy, dummy) \
|
||||
imaginary(WasmMemory, 51, dummy, dummy) \
|
||||
IF_PROMISE(real,imaginary)(Promise, 52, InitViaClassSpec, OCLASP(Promise)) \
|
||||
imaginary(WasmTable, 52, dummy, dummy) \
|
||||
IF_PROMISE(real,imaginary)(Promise, 53, InitViaClassSpec, OCLASP(Promise)) \
|
||||
|
||||
#define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro)
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче