From bc488987a0ff7975cff70b1034ef2d7fbbd63445 Mon Sep 17 00:00:00 2001 From: Daniel Wirtz Date: Tue, 3 Sep 2019 01:21:35 +0200 Subject: [PATCH] Update loader with what we've learned (#810) --- lib/loader/README.md | 127 ++++++++------------------- lib/loader/index.d.ts | 72 +++++++-------- lib/loader/index.js | 178 +++++++++++++++++--------------------- lib/loader/tests/index.js | 11 --- 4 files changed, 151 insertions(+), 237 deletions(-) diff --git a/lib/loader/README.md b/lib/loader/README.md index 141256ddc4..130c6b090a 100644 --- a/lib/loader/README.md +++ b/lib/loader/README.md @@ -30,76 +30,6 @@ API Besides demangling classes exported from your entry file to a handy object structure one can use like JS objects, instances are automatically populated with useful utility: -* **I8**: `Int8Array`
- An 8-bit signed integer view on the memory. - - ```ts - var value = module.I8[ptr]; - ``` - -* **U8**: `Uint8Array`
- An 8-bit unsigned integer view on the memory. - - ```ts - var value = module.U8[ptr]; - ``` - -* **I16**: `Int16Array`
- A 16-bit signed integer view on the memory. - - ```ts - var value = module.I16[ptr >>> 1]; - ``` - -* **U16**: `Uint16Array`
- A 16-bit unsigned integer view on the memory. - - ```ts - var value = module.U16[ptr >>> 1]; - ``` - -* **I32**: `Int32Array`
- A 32-bit signed integer view on the memory. - - ```ts - var value = module.I32[ptr >>> 2]; - ``` - -* **U32**: `Uint32Array`
- A 32-bit unsigned integer view on the memory. - - ```ts - var value = module.U32[ptr >>> 2]; - ``` - -* **I64**: `BigInt64Array`
- A 64-bit signed integer view on the memory, if supported by the VM. - - ```ts - var value = module.I64[ptr >>> 3]; - ``` - -* **U64**: `BigUint64Array`
- A 64-bit unsigned integer view on the memory, if supported by the VM. - - ```ts - var value = module.U64[ptr >>> 3]; - ``` - -* **F32**: `Float32Array`
- A 32-bit float view on the memory. - - ```ts - var value = module.I32[ptr >>> 2]; - ``` - -* **F64**: `Float64Array`
- A 64-bit float view on the memory. - - ```ts - var value = module.F64[ptr >>> 3]; - ``` - * **__start**(): `void`
Explicit start function if the `--explicitStart` option is used. Must be called before any other exports if present. @@ -107,16 +37,16 @@ Besides demangling classes exported from your entry file to a handy object struc Allocates a new string in the module's memory and returns a reference (pointer) to it. ```ts - var ref = module.__retain(module.__allocString("hello world")); + var ptr = module.__retain(module.__allocString("hello world")); ... - module.__release(ref); + module.__release(ptr); ``` -* **__getString**(ref: `number`): `string`
+* **__getString**(ptr: `number`): `string`
Reads (copies) the value of a string from the module's memory. ```ts - var str = module.__getString(ref); + var str = module.__getString(ptr); ... ``` @@ -125,44 +55,63 @@ Besides demangling classes exported from your entry file to a handy object struc Automatically retains interior pointers. The `id` is the unique runtime id of the respective array class. If you are using `Int32Array` for example, the best way to know the id is an `export const INT32ARRAY_ID = idof()`. When done with the array, make sure to release it. ```ts - var ref = module.__retain(module.__allocArray(module.INT32ARRAY, [1, 2, 3])); + var ptr = module.__retain(module.__allocArray(module.INT32ARRAY, [1, 2, 3])); ... - module.__release(ref); + module.__release(ptr); ``` -* **__getArray**(ref: `number`): `number[]`
+* **__getArray**(ptr: `number`): `number[]`
Reads (copies) the values of an array from the module's memory. ```ts - var arr = module.__getArray(ref); + var arr = module.__getArray(ptr); ... ``` -* **__getArrayView**(ref: `number`): `TypedArray`
+* **__getArrayView**(ptr: `number`): `TypedArray`
Gets a view on the values of an array in the module's memory. This differs from `__getArray` in that the data isn't copied but remains *live* in both directions. That's faster but also unsafe because if the array grows or becomes released, the view will no longer represent the correct memory region and modifying its values in this state will most likely corrupt memory. Use, but use with care. -* **__retain**(ref: `number`): `number`
- Retains a reference externally, making sure that it doesn't become collected prematurely. Returns the reference. + If the type of the array is known beforehand, the following even faster and even more unsafe helpers can be used that don't do any type checking: + + **__getInt8Array**(ptr: `number`): `Int8Array`
+ **__getUint8Array**(ptr: `number`): `Uint8Array`
+ **__getUint8ClampedArray**(ptr: `number`): `Uint8ClampedArray`
+ **__getInt16Array**(ptr: `number`): `Int16Array`
+ **__getUint16Array**(ptr: `number`): `Uint16Array`
+ **__getInt32Array**(ptr: `number`): `Int32Array`
+ **__getUint32Array**(ptr: `number`): `Uint32Array`
+ **__getInt64Array**(ptr: `number`): `BigInt64Array`
+ **__getUint64Array**(ptr: `number`): `BigUint64Array`
+ **__getFloat32Array**(ptr: `number`): `Float32Array`
+ **__getFloat64Array**(ptr: `number`): `Float64Array` + +* **__getArrayBuffer**(ptr: `number`): `ArrayBuffer`
+ Reads (copies) the data of an ArrayBuffer from the module's memory. + +* **__retain**(ptr: `number`): `number`
+ Retains a reference to a managed object externally, making sure that it doesn't become collected prematurely. Returns the pointer. -* **__release**(ref: `number`): `void`
- Releases a previously retained reference to an object, allowing the runtime to collect it once its reference count reaches zero. +* **__release**(ptr: `number`): `void`
+ Releases a previously retained reference to a managed object, allowing the runtime to collect it once its reference count reaches zero. * **__alloc**(size: `number`, id: `number`): `number`
Allocates an instance of the class represented by the specified id. If you are using `MyClass` for example, the best way to know the id and the necessary size is an `export const MYCLASS_ID = idof()` and an `export const MYCLASS_SIZE = offsetof()`. Afterwards, use the respective views to assign values to the class's memory while making sure to retain interior references to other managed objects once. When done with the class, make sure to release it, which will automatically release any interior references once the class becomes collected. ```ts - var ref = module.__retain(module.__alloc(module.MYCLASS_SIZE, module.MYCLASS_ID)); - F32[ref + MYCLASS_BASICFIELD1_OFFSET >>> 2] = field1_value_f32; - U32[ref + MYCLASS_MANAGEDFIELD2_OFFSET >>> 2] = module.__retain(field2_value_ref); + var ptr = module.__retain(module.__alloc(module.MYCLASS_SIZE, module.MYCLASS_ID)); + const F32 = new Float32Array(module.memory.buffer); + F32[ptr + MYCLASS_BASICFIELD1_OFFSET >>> 2] = field1_value_f32; + const U32 = new Uint32Array(module.memory.buffer); + U32[ptr + MYCLASS_MANAGEDFIELD2_OFFSET >>> 2] = module.__retain(field2_value_ptr); ... - module.__release(ref); + module.__release(ptr); ``` -* **__instanceof**(ref: `number`, baseId: `number`): `boolean`
+* **__instanceof**(ptr: `number`, baseId: `number`): `boolean`
Tests whether an object is an instance of the class represented by the specified base id. ```ts - if (module.__instanceof(ref, module.MYCLASS_ID)) { + if (module.__instanceof(ptr, module.MYCLASS_ID)) { ... } ``` diff --git a/lib/loader/index.d.ts b/lib/loader/index.d.ts index 0ce0221a0a..0c622913be 100644 --- a/lib/loader/index.d.ts +++ b/lib/loader/index.d.ts @@ -1,3 +1,5 @@ +/// + import "@types/webassembly-js-api"; /** WebAssembly imports with two levels of nesting. */ @@ -19,66 +21,56 @@ type TypedArray | Int32Array | Uint32Array | Float32Array - | Float64Array; + | Float64Array + | BigInt64Array + | BigUint64Array; /** Utility mixed in by the loader. */ interface ASUtil { - /** An 8-bit signed integer view on the memory. */ - readonly I8: Uint8Array; - /** An 8-bit unsigned integer view on the memory. */ - readonly U8: Uint8Array; - /** A 16-bit signed integer view on the memory. */ - readonly I16: Uint16Array; - /** A 16-bit unsigned integer view on the memory. */ - readonly U16: Uint16Array; - /** A 32-bit signed integer view on the memory. */ - readonly I32: Uint32Array; - /** A 32-bit unsigned integer view on the memory. */ - readonly U32: Uint32Array; - /** A 64-bit signed integer view on the memory. */ - readonly I64: any; // BigInt64Array - /** A 64-bit unsigned integer vieww on the memory. */ - readonly U64: any; // BigUint64Array - /** A 32-bit float view on the memory. */ - readonly F32: Float32Array; - /** A 64-bit float view on the memory. */ - readonly F64: Float64Array; /** Explicit start function, if requested. */ __start(): void; /** Allocates a new string in the module's memory and returns a reference (pointer) to it. */ __allocString(str: string): number; /** Reads (copies) the value of a string from the module's memory. */ - __getString(ref: number): string; + __getString(ptr: number): string; /** Allocates a new array in the module's memory and returns a reference (pointer) to it. */ __allocArray(id: number, values: number[]): number; /** Reads (copies) the values of an array from the module's memory. */ - __getArray(ref: number): number[]; + __getArray(ptr: number): number[]; /** Gets a view on the values of an array in the module's memory. */ - __getArrayView(ref: number): TypedArray; - /** Reads (copies) the values of Uint8Array from the module's memory. */ - __getUint8Array(ref: number): Uint8Array; + __getArrayView(ptr: number): TypedArray; /** Reads (copies) the values of Int8Array from the module's memory. */ - __getInt8Array(ref: number): Int8Array; - /** Reads (copies) the values of Uint16Array from the module's memory. */ - __getUint16Array(ref: number): Uint16Array; + __getInt8Array(ptr: number): Int8Array; + /** Reads (copies) the values of Uint8Array from the module's memory. */ + __getUint8Array(ptr: number): Uint8Array; + /** Reads (copies) the values of Uint8Array from the module's memory. */ + __getUint8ClampedArray(ptr: number): Uint8ClampedArray; /** Reads (copies) the values of Int16Array from the module's memory. */ - __getInt16Array(ref: number): Int16Array; + __getInt16Array(ptr: number): Int16Array; + /** Reads (copies) the values of Uint16Array from the module's memory. */ + __getUint16Array(ptr: number): Uint16Array; + /** Reads (copies) the values of Int32Array from the module's memory. */ + __getInt32Array(ptr: number): Int32Array; /** Reads (copies) the values of Uint32Array from the module's memory. */ - __getUint32Array(ref: number): Uint32Array; + __getUint32Array(ptr: number): Uint32Array; /** Reads (copies) the values of Int32Array from the module's memory. */ - __getInt32Array(ref: number): Int32Array; + __getInt64Array(ptr: number): BigInt32Array; + /** Reads (copies) the values of Uint32Array from the module's memory. */ + __getUint64Array(ptr: number): BigUint32Array; /** Reads (copies) the values of Float32Array from the module's memory. */ - __getFloat32Array(ref: number): Float32Array; + __getFloat32Array(ptr: number): Float32Array; /** Reads (copies) the values of Float64Array from the module's memory. */ - __getFloat64Array(ref: number): Float64Array; - /** Retains a reference externally, making sure that it doesn't become collected prematurely. Returns the reference. */ - __retain(ref: number): number; - /** Releases a previously retained reference to an object, allowing the runtime to collect it once its reference count reaches zero. */ - __release(ref: number): void; + __getFloat64Array(ptr: number): Float64Array; + /** Reads (copies) the data of an ArrayBuffer from the module's memory. */ + __getArrayBuffer(ptr: number): ArrayBuffer; + /** Retains a reference to a managed object externally, making sure that it doesn't become collected prematurely. Returns the pointer. */ + __retain(ptr: number): number; + /** Releases a previously retained reference to a managed object, allowing the runtime to collect it once its reference count reaches zero. */ + __release(ptr: number): void; /** Allocates an instance of the class represented by the specified id. */ __alloc(size: number, id: number): number; - /** Tests whether an object is an instance of the class represented by the specified base id. */ - __instanceof(ref: number, baseId: number): boolean; + /** Tests whether a managed object is an instance of the class represented by the specified base id. */ + __instanceof(ptr: number, baseId: number): boolean; /** Forces a cycle collection. Only relevant if objects potentially forming reference cycles are used. */ __collect(): void; } diff --git a/lib/loader/index.js b/lib/loader/index.js index 2a759abd21..434fb5fed1 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -14,18 +14,18 @@ const ARRAYBUFFERVIEW = 1 << 0; const ARRAY = 1 << 1; const SET = 1 << 2; const MAP = 1 << 3; -const VAL_ALIGN = 1 << 5; +const VAL_ALIGN_OFFSET = 5; +const VAL_ALIGN = 1 << VAL_ALIGN_OFFSET; const VAL_SIGNED = 1 << 10; const VAL_FLOAT = 1 << 11; const VAL_NULLABLE = 1 << 12; const VAL_MANAGED = 1 << 13; -const KEY_ALIGN = 1 << 14; +const KEY_ALIGN_OFFSET = 14; +const KEY_ALIGN = 1 << KEY_ALIGN_OFFSET; const KEY_SIGNED = 1 << 19; const KEY_FLOAT = 1 << 20; const KEY_NULLABLE = 1 << 21; const KEY_MANAGED = 1 << 22; -const KEY_ALIGN_OFFSET = 14; -const VAL_ALIGN_OFFSET = 5; // Array(BufferView) layout const ARRAYBUFFERVIEW_BUFFER_OFFSET = 0; @@ -40,9 +40,11 @@ const THIS = Symbol(); const CHUNKSIZE = 1024; /** Gets a string from an U32 and an U16 view on a memory. */ -function getStringImpl(U32, U16, ref) { - var length = U32[(ref + SIZE_OFFSET) >>> 2] >>> 1; - var offset = ref >>> 1; +function getStringImpl(buffer, ptr) { + const U32 = new Uint32Array(buffer); + const U16 = new Uint16Array(buffer); + var length = U32[(ptr + SIZE_OFFSET) >>> 2] >>> 1; + var offset = ptr >>> 1; if (length <= CHUNKSIZE) return String.fromCharCode.apply(String, U16.subarray(offset, offset + length)); const parts = []; do { @@ -58,10 +60,9 @@ function getStringImpl(U32, U16, ref) { function preInstantiate(imports) { const baseModule = {}; - function getString(memory, ref) { + function getString(memory, ptr) { if (!memory) return ""; - const buffer = memory.buffer; - return getStringImpl(new Uint32Array(buffer), new Uint16Array(buffer), ref); + return getStringImpl(memory.buffer, ptr); } // add common imports used by stdlib for convenience @@ -89,33 +90,9 @@ function postInstantiate(baseModule, instance) { const retain = rawExports["__retain"]; const rttiBase = rawExports["__rtti_base"] || ~0; // oob if not present - // Provide views for all sorts of basic values - var buffer, I8, U8, I16, U16, I32, U32, F32, F64, I64, U64; - - /** Updates memory views if memory has grown meanwhile. */ - function checkMem() { - // see: https://github.com/WebAssembly/design/issues/1210 - if (buffer !== memory.buffer) { - buffer = memory.buffer; - I8 = new Int8Array(buffer); - U8 = new Uint8Array(buffer); - I16 = new Int16Array(buffer); - U16 = new Uint16Array(buffer); - I32 = new Int32Array(buffer); - U32 = new Uint32Array(buffer); - if (BIGINT) { - I64 = new BigInt64Array(buffer); - U64 = new BigUint64Array(buffer); - } - F32 = new Float32Array(buffer); - F64 = new Float64Array(buffer); - } - } - - checkMem(); - /** Gets the runtime type info for the given id. */ function getInfo(id) { + const U32 = new Uint32Array(memory.buffer); const count = U32[rttiBase >>> 2]; if ((id >>>= 0) >= count) throw Error("invalid id: " + id); return U32[(rttiBase + 4 >>> 2) + id * 2]; @@ -123,79 +100,71 @@ function postInstantiate(baseModule, instance) { /** Gets the runtime base id for the given id. */ function getBase(id) { + const U32 = new Uint32Array(memory.buffer); const count = U32[rttiBase >>> 2]; if ((id >>>= 0) >= count) throw Error("invalid id: " + id); return U32[(rttiBase + 4 >>> 2) + id * 2 + 1]; } /** Gets the runtime alignment of a collection's values. */ - function getAlignValue(info) { + function getValueAlign(info) { return 31 - Math.clz32((info >>> VAL_ALIGN_OFFSET) & 31); // -1 if none } /** Gets the runtime alignment of a collection's keys. */ - function getAlignKey(info) { + function getKeyAlign(info) { return 31 - Math.clz32((info >>> KEY_ALIGN_OFFSET) & 31); // -1 if none } - function getTypedArray(Type, shift, arr) { - var buffer = memory.buffer; - var u32 = new Uint32Array(buffer); - var buf = u32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2]; - var length = u32[buf + SIZE_OFFSET >>> 2]; - return new Type(buffer).slice(buf >>> shift, buf + length >>> shift); - } - /** Allocates a new string in the module's memory and returns its retained pointer. */ function __allocString(str) { - var length = str.length; - var ref = alloc(length << 1, STRING_ID); - var u16 = new Uint16Array(memory.buffer); - for (var i = 0, p = ref >>> 1; i < length; ++i) u16[p + i] = str.charCodeAt(i); - return ref; + const length = str.length; + const ptr = alloc(length << 1, STRING_ID); + const U16 = new Uint16Array(memory.buffer); + for (var i = 0, p = ptr >>> 1; i < length; ++i) U16[p + i] = str.charCodeAt(i); + return ptr; } baseModule.__allocString = __allocString; /** Reads a string from the module's memory by its pointer. */ - function __getString(ref) { - var buf = memory.buffer; - var u16 = new Uint16Array(buf); - var u32 = new Uint32Array(buf); - var id = u32[ref + ID_OFFSET >>> 2]; - if (id !== STRING_ID) throw Error("not a string: " + ref); - return getStringImpl(u32, u16, ref); + function __getString(ptr) { + const buffer = memory.buffer; + const id = new Uint32Array(buffer)[ptr + ID_OFFSET >>> 2]; + if (id !== STRING_ID) throw Error("not a string: " + ptr); + return getStringImpl(buffer, ptr); } baseModule.__getString = __getString; /** Gets the view matching the specified alignment, signedness and floatness. */ - function getView(align, signed, float) { + function getView(alignLog2, signed, float) { + const buffer = memory.buffer; if (float) { - switch (align) { - case 2: return F32; - case 3: return F64; + switch (alignLog2) { + case 2: return new Float32Array(buffer); + case 3: return new Float64Array(buffer); } } else { - switch (align) { - case 0: return signed ? I8 : U8; - case 1: return signed ? I16 : U16; - case 2: return signed ? I32 : U32; - case 3: return signed ? I64 : U64; + switch (alignLog2) { + case 0: return new (signed ? Int8Array : Uint8Array)(buffer); + case 1: return new (signed ? Int16Array : Uint16Array)(buffer); + case 2: return new (signed ? Int32Array : Uint32Array)(buffer); + case 3: return new (signed ? BigInt64Array : BigUint64Array)(buffer); } } - throw Error("unsupported align: " + align); + throw Error("unsupported align: " + alignLog2); } /** Allocates a new array in the module's memory and returns its retained pointer. */ function __allocArray(id, values) { const info = getInfo(id); if (!(info & (ARRAYBUFFERVIEW | ARRAY))) throw Error("not an array: " + id + " @ " + info); - const align = getAlignValue(info); + const align = getValueAlign(info); const length = values.length; const buf = alloc(length << align, ARRAYBUFFER_ID); const arr = alloc(info & ARRAY ? ARRAY_SIZE : ARRAYBUFFERVIEW_SIZE, id); - checkMem(); + const U32 = new Uint32Array(memory.buffer); U32[arr + ARRAYBUFFERVIEW_BUFFER_OFFSET >>> 2] = retain(buf); U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2] = buf; U32[arr + ARRAYBUFFERVIEW_DATALENGTH_OFFSET >>> 2] = length << align; @@ -213,11 +182,11 @@ function postInstantiate(baseModule, instance) { /** Gets a view on the values of an array in the module's memory. */ function __getArrayView(arr) { - checkMem(); + const U32 = new Uint32Array(memory.buffer); const id = U32[arr + ID_OFFSET >>> 2]; const info = getInfo(id); if (!(info & ARRAYBUFFERVIEW)) throw Error("not an array: " + id); - const align = getAlignValue(info); + const align = getValueAlign(info); var buf = U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2]; const length = info & ARRAY ? U32[arr + ARRAY_LENGTH_OFFSET >>> 2] @@ -235,26 +204,52 @@ function postInstantiate(baseModule, instance) { baseModule.__getArray = __getArray; - function __getArrayBuffer(buf) { - var buffer = memory.buffer; - var length = (new Uint32Array(buffer))[buf + SIZE_OFFSET >>> 2]; - return buffer.slice(buf, buf + length); + /** Reads (copies) the data of an ArrayBuffer from the module's memory. */ + function __getArrayBuffer(ptr) { + const buffer = memory.buffer; + const length = new Uint32Array(buffer)[ptr + SIZE_OFFSET >>> 2]; + return buffer.slice(ptr, ptr + length); } baseModule.__getArrayBuffer = __getArrayBuffer; - baseModule.__getUint8Array = getTypedArray.bind(null, Uint8Array, 0); - baseModule.__getInt8Array = getTypedArray.bind(null, Int8Array, 0); - baseModule.__getUint16Array = getTypedArray.bind(null, Uint16Array, 1); - baseModule.__getInt16Array = getTypedArray.bind(null, Int16Array, 1); - baseModule.__getUint32Array = getTypedArray.bind(null, Uint32Array, 2); - baseModule.__getInt32Array = getTypedArray.bind(null, Int32Array, 2); - baseModule.__getFloat32Array = getTypedArray.bind(null, Float32Array, 2); - baseModule.__getFloat64Array = getTypedArray.bind(null, Float64Array, 3); + function getTypedArrayImpl(Type, alignLog2, ptr) { + const buffer = memory.buffer; + const U32 = new Uint32Array(buffer); + const bufPtr = U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2]; + const length = U32[bufPtr + SIZE_OFFSET >>> 2]; + return new Type(buffer).slice(bufPtr >>> alignLog2, bufPtr + length >>> alignLog2); + } + + /** Gets a view on the values of a known-to-be Int8Array in the module's memory. */ + baseModule.__getInt8Array = getTypedArrayImpl.bind(null, Int8Array, 0); + /** Gets a view on the values of a known-to-be Uint8Array in the module's memory. */ + baseModule.__getUint8Array = getTypedArrayImpl.bind(null, Uint8Array, 0); + /** Gets a view on the values of a known-to-be Uint8ClampedArray in the module's memory. */ + baseModule.__getUint8ClampedArray = getTypedArrayImpl.bind(null, Uint8ClampedArray, 0); + /** Gets a view on the values of a known-to-be Int16Array in the module's memory. */ + baseModule.__getInt16Array = getTypedArrayImpl.bind(null, Int16Array, 1); + /** Gets a view on the values of a known-to-be Uint16Array in the module's memory. */ + baseModule.__getUint16Array = getTypedArrayImpl.bind(null, Uint16Array, 1); + /** Gets a view on the values of a known-to-be Int32Array in the module's memory. */ + baseModule.__getInt32Array = getTypedArrayImpl.bind(null, Int32Array, 2); + /** Gets a view on the values of a known-to-be Uint32Array in the module's memory. */ + baseModule.__getUint32Array = getTypedArrayImpl.bind(null, Uint32Array, 2); + if (BIGINT) { + /** Gets a view on the values of a known-to-be-Int64Array in the module's memory. */ + baseModule.__getInt64Array = getTypedArrayImpl.bind(null, BigInt64Array, 3); + /** Gets a view on the values of a known-to-be-Uint64Array in the module's memory. */ + baseModule.__getUint64Array = getTypedArrayImpl.bind(null, BigUint64Array, 3); + } + /** Gets a view on the values of a known-to-be Float32Array in the module's memory. */ + baseModule.__getFloat32Array = getTypedArrayImpl.bind(null, Float32Array, 2); + /** Gets a view on the values of a known-to-be Float64Array in the module's memory. */ + baseModule.__getFloat64Array = getTypedArrayImpl.bind(null, Float64Array, 3); /** Tests whether an object is an instance of the class represented by the specified base id. */ - function __instanceof(ref, baseId) { - var id = U32[(ref + ID_OFFSET) >>> 2]; + function __instanceof(ptr, baseId) { + const U32 = new Uint32Array(memory.buffer); + var id = U32[(ptr + ID_OFFSET) >>> 2]; if (id <= U32[rttiBase >>> 2]) { do if (id == baseId) return true; while (id = getBase(id)); @@ -269,18 +264,7 @@ function postInstantiate(baseModule, instance) { baseModule.table = baseModule.table || table; // Demangle exports and provide the usual utility on the prototype - return demangle(rawExports, Object.defineProperties(baseModule, { - I8: { get: function() { checkMem(); return I8; } }, - U8: { get: function() { checkMem(); return U8; } }, - I16: { get: function() { checkMem(); return I16; } }, - U16: { get: function() { checkMem(); return U16; } }, - I32: { get: function() { checkMem(); return I32; } }, - U32: { get: function() { checkMem(); return U32; } }, - I64: { get: function() { checkMem(); return I64; } }, - U64: { get: function() { checkMem(); return U64; } }, - F32: { get: function() { checkMem(); return F32; } }, - F64: { get: function() { checkMem(); return F64; } } - })); + return demangle(rawExports, baseModule); } /** Wraps a WebAssembly function while also taking care of variable arguments. */ diff --git a/lib/loader/tests/index.js b/lib/loader/tests/index.js index fddf10d8d4..f61875e042 100644 --- a/lib/loader/tests/index.js +++ b/lib/loader/tests/index.js @@ -8,17 +8,6 @@ var module = loader.instantiateBuffer(buffer, {}); console.log(inspect(module, true, 100, true)); -// should inherit the usual utility -var proto = Object.getPrototypeOf(module); -assert(proto.I8 instanceof Int8Array); -assert(proto.U8 instanceof Uint8Array); -assert(proto.I16 instanceof Int16Array); -assert(proto.U16 instanceof Uint16Array); -assert(proto.I32 instanceof Int32Array); -assert(proto.U32 instanceof Uint32Array); -assert(proto.F32 instanceof Float32Array); -assert(proto.F64 instanceof Float64Array); - // should export memory assert(module.memory instanceof WebAssembly.Memory); assert(typeof module.memory.copy === "function");