diff --git a/lib/loader/index.d.ts b/lib/loader/index.d.ts index 0c622913be..bc7458f933 100644 --- a/lib/loader/index.d.ts +++ b/lib/loader/index.d.ts @@ -12,6 +12,19 @@ interface ImportsObject extends Record { } } +interface Memory extends WebAssembly.Memory { + U8: Uint8Array; + I8: Iint8Array; + U16: Uint16Array; + I16: Iint16Array; + U32: Uint32Array; + I32: Int32Array; + U64: BigUint64Array; + I64: BigInt64Array; + F32: Float32Array; + F64: Float64Array; +} + type TypedArray = Int8Array | Uint8Array @@ -73,6 +86,8 @@ interface ASUtil { __instanceof(ptr: number, baseId: number): boolean; /** Forces a cycle collection. Only relevant if objects potentially forming reference cycles are used. */ __collect(): void; + /** Memory with different views. */ + memory: Memory; } /** Instantiates an AssemblyScript module using the specified imports. */ diff --git a/lib/loader/index.js b/lib/loader/index.js index 6a51c1291b..6e4345b885 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -90,9 +90,63 @@ function postInstantiate(baseModule, instance) { const retain = rawExports["__retain"]; const rttiBase = rawExports["__rtti_base"] || ~0; // oob if not present + Object.defineProperties(memory, // Different view of memory + { + U8: { + get: function(){ + return new Uint8Array(this.buffer); + } + }, + I8: { + get: function(){ + return new Int8Array(this.buffer); + } + }, + U16: { + get: function(){ + return new Uint16Array(this.buffer); + } + }, + I16: { + get: function(){ + return new Int16Array(this.buffer); + } + }, + U32: { + get: function(){ + return new Uint32Array(this.buffer); + } + }, + I32: { + get: function(){ + return new Int32Array(this.buffer); + } + }, + U64: { + get: function(){ + return new BigUint64Array(this.buffer); + } + }, + I64: { + get: function(){ + return new BigInt64Array(this.buffer); + } + }, + F32: { + get: function(){ + return new Float32Array(this.buffer); + } + }, + F64: { + get: function(){ + return new Float64Array(this.buffer); + } + }, + }) + /** Gets the runtime type info for the given id. */ function getInfo(id) { - const U32 = new Uint32Array(memory.buffer); + const U32 = memory.U32; const count = U32[rttiBase >>> 2]; if ((id >>>= 0) >= count) throw Error("invalid id: " + id); return U32[(rttiBase + 4 >>> 2) + id * 2]; @@ -100,7 +154,7 @@ function postInstantiate(baseModule, instance) { /** Gets the runtime base id for the given id. */ function getBase(id) { - const U32 = new Uint32Array(memory.buffer); + const U32 = memory.U32; const count = U32[rttiBase >>> 2]; if ((id >>>= 0) >= count) throw Error("invalid id: " + id); return U32[(rttiBase + 4 >>> 2) + id * 2 + 1]; @@ -120,7 +174,7 @@ function postInstantiate(baseModule, instance) { function __allocString(str) { const length = str.length; const ptr = alloc(length << 1, STRING_ID); - const U16 = new Uint16Array(memory.buffer); + const U16 = memory.U16 for (var i = 0, p = ptr >>> 1; i < length; ++i) U16[p + i] = str.charCodeAt(i); return ptr; } @@ -130,7 +184,7 @@ function postInstantiate(baseModule, instance) { /** Reads a string from the module's memory by its pointer. */ function __getString(ptr) { const buffer = memory.buffer; - const id = new Uint32Array(buffer)[ptr + ID_OFFSET >>> 2]; + const id = memory.U32[ptr + ID_OFFSET >>> 2]; if (id !== STRING_ID) throw Error("not a string: " + ptr); return getStringImpl(buffer, ptr); } @@ -139,18 +193,17 @@ function postInstantiate(baseModule, instance) { /** Gets the view matching the specified alignment, signedness and floatness. */ function getView(alignLog2, signed, float) { - const buffer = memory.buffer; if (float) { switch (alignLog2) { - case 2: return new Float32Array(buffer); - case 3: return new Float64Array(buffer); + case 2: return memory.F32; + case 3: return memory.F64; } } else { 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); + case 0: return signed ? memory.I8 : memory.U8; + case 1: return signed ? memory.I16 : memory.U16; + case 2: return signed ? memory.I32 : memory.U32; + case 3: return signed ? memory.I64 : memory.U64; } } throw Error("unsupported align: " + alignLog2); @@ -164,7 +217,7 @@ function postInstantiate(baseModule, instance) { const length = values.length; const buf = alloc(length << align, ARRAYBUFFER_ID); const arr = alloc(info & ARRAY ? ARRAY_SIZE : ARRAYBUFFERVIEW_SIZE, id); - const U32 = new Uint32Array(memory.buffer); + const U32 = memory.U32; U32[arr + ARRAYBUFFERVIEW_BUFFER_OFFSET >>> 2] = retain(buf); U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2] = buf; U32[arr + ARRAYBUFFERVIEW_DATALENGTH_OFFSET >>> 2] = length << align; @@ -182,7 +235,7 @@ function postInstantiate(baseModule, instance) { /** Gets a view on the values of an array in the module's memory. */ function __getArrayView(arr) { - const U32 = new Uint32Array(memory.buffer); + const U32 = memory.U32; const id = U32[arr + ID_OFFSET >>> 2]; const info = getInfo(id); if (!(info & ARRAYBUFFERVIEW)) throw Error("not an array: " + id); @@ -211,18 +264,17 @@ function postInstantiate(baseModule, instance) { /** 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]; + const length = memory.U32[ptr + SIZE_OFFSET >>> 2]; return buffer.slice(ptr, ptr + length); } baseModule.__getArrayBuffer = __getArrayBuffer; function getTypedArrayImpl(Type, alignLog2, ptr) { - const buffer = memory.buffer; - const U32 = new Uint32Array(buffer); + const U32 = memory.U32; 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); + return new Type(memory.buffer).slice(bufPtr >>> alignLog2, bufPtr + length >>> alignLog2); } /** Gets a view on the values of a known-to-be Int8Array in the module's memory. */ @@ -252,7 +304,7 @@ function postInstantiate(baseModule, instance) { /** Tests whether an object is an instance of the class represented by the specified base id. */ function __instanceof(ptr, baseId) { - const U32 = new Uint32Array(memory.buffer); + const U32 = memory.U32; var id = U32[(ptr + ID_OFFSET) >>> 2]; if (id <= U32[rttiBase >>> 2]) { do if (id == baseId) return true; diff --git a/lib/loader/tests/index.js b/lib/loader/tests/index.js index f61875e042..977593132e 100644 --- a/lib/loader/tests/index.js +++ b/lib/loader/tests/index.js @@ -14,6 +14,8 @@ assert(typeof module.memory.copy === "function"); // should be able to get an exported string assert.strictEqual(module.__getString(module.COLOR), "red"); +assert.deepEqual(module.memory.U8, new Uint8Array(module.memory.buffer)) +assert.deepEqual(module.memory.F32, new Float32Array(module.memory.buffer)) // should be able to allocate and work with a new string {