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:
Luke Wagner 2016-07-12 20:20:14 -05:00
Родитель 9105b9d2ea
Коммит 1b4ff6fb6f
6 изменённых файлов: 185 добавлений и 18 удалений

Просмотреть файл

@ -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)