diff --git a/lib/loader/index.d.ts b/lib/loader/index.d.ts index e494b13a28..5e2f883c2e 100644 --- a/lib/loader/index.d.ts +++ b/lib/loader/index.d.ts @@ -1,5 +1,10 @@ /// +interface ResultObject { + module: WebAssembly.Module, + instance: WebAssembly.Instance +}; + /** WebAssembly imports with two levels of nesting. */ interface ImportsObject extends Record { env?: { @@ -92,13 +97,22 @@ interface ASUtil { } /** Asynchronously instantiates an AssemblyScript module from anything that can be instantiated. */ -export declare function instantiate(source: WebAssembly.Module | BufferSource | Response | PromiseLike, imports?: ImportsObject): Promise; +export declare function instantiate( + source: WebAssembly.Module | BufferSource | Response | PromiseLike, + imports?: ImportsObject +): Promise; /** Synchronously instantiates an AssemblyScript module from a WebAssembly.Module or binary buffer. */ -export declare function instantiateSync(source: WebAssembly.Module | BufferSource, imports?: ImportsObject): ASUtil & T; +export declare function instantiateSync( + source: WebAssembly.Module | BufferSource, + imports?: ImportsObject +): ResultObject & { exports: ASUtil & T }; /** Asynchronously instantiates an AssemblyScript module from a response, i.e. as obtained by `fetch`. */ -export declare function instantiateStreaming(source: Response | PromiseLike, imports?: ImportsObject): Promise; +export declare function instantiateStreaming( + source: Response | PromiseLike, + imports?: ImportsObject +): Promise; /** Demangles an AssemblyScript module's exports to a friendly object structure. */ -export declare function demangle(exports: {}, baseModule?: {}): T; +export declare function demangle(exports: {}, extendedExports?: {}): T; diff --git a/lib/loader/index.js b/lib/loader/index.js index 96312c2a0b..2f9e38e46f 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -43,8 +43,8 @@ const CHUNKSIZE = 1024; 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; + let length = U32[(ptr + SIZE_OFFSET) >>> 2] >>> 1; + let offset = ptr >>> 1; if (length <= CHUNKSIZE) return String.fromCharCode.apply(String, U16.subarray(offset, offset + length)); const parts = []; do { @@ -58,7 +58,7 @@ function getStringImpl(buffer, ptr) { /** Prepares the base module prior to instantiation. */ function preInstantiate(imports) { - const baseModule = {}; + const extendedExports = {}; function getString(memory, ptr) { if (!memory) return ""; @@ -67,13 +67,13 @@ function preInstantiate(imports) { // add common imports used by stdlib for convenience const env = (imports.env = imports.env || {}); - env.abort = env.abort || function abort(mesg, file, line, colm) { - const memory = baseModule.memory || env.memory; // prefer exported, otherwise try imported - throw Error("abort: " + getString(memory, mesg) + " in " + getString(memory, file) + "(" + line + ":" + colm + ")"); + env.abort = env.abort || function abort(msg, file, line, colm) { + const memory = extendedExports.memory || env.memory; // prefer exported, otherwise try imported + throw Error("abort: " + getString(memory, msg) + " at " + getString(memory, file) + ":" + line + ":" + colm); }; - env.trace = env.trace || function trace(mesg, n) { - const memory = baseModule.memory || env.memory; - console.log("trace: " + getString(memory, mesg) + (n ? " " : "") + Array.prototype.slice.call(arguments, 2, 2 + n).join(", ")); + env.trace = env.trace || function trace(msg, n) { + const memory = extendedExports.memory || env.memory; + console.log("trace: " + getString(memory, msg) + (n ? " " : "") + Array.prototype.slice.call(arguments, 2, 2 + n).join(", ")); }; env.seed = env.seed || function seed() { return Date.now(); @@ -81,17 +81,17 @@ function preInstantiate(imports) { imports.Math = imports.Math || Math; imports.Date = imports.Date || Date; - return baseModule; + return extendedExports; } /** Prepares the final module once instantiation is complete. */ -function postInstantiate(baseModule, instance) { - const rawExports = instance.exports; - const memory = rawExports.memory; - const table = rawExports.table; - const alloc = rawExports["__alloc"]; - const retain = rawExports["__retain"]; - const rttiBase = rawExports["__rtti_base"] || ~0; // oob if not present +function postInstantiate(extendedExports, instance) { + const exports = instance.exports; + const memory = exports.memory; + const table = exports.table; + const alloc = exports["__alloc"]; + const retain = exports["__retain"]; + const rttiBase = exports["__rtti_base"] || ~0; // oob if not present /** Gets the runtime type info for the given id. */ function getInfo(id) { @@ -128,7 +128,7 @@ function postInstantiate(baseModule, instance) { return ptr; } - baseModule.__allocString = __allocString; + extendedExports.__allocString = __allocString; /** Reads a string from the module's memory by its pointer. */ function __getString(ptr) { @@ -138,7 +138,7 @@ function postInstantiate(baseModule, instance) { return getStringImpl(buffer, ptr); } - baseModule.__getString = __getString; + extendedExports.__getString = __getString; /** Gets the view matching the specified alignment, signedness and floatness. */ function getView(alignLog2, signed, float) { @@ -181,7 +181,7 @@ function postInstantiate(baseModule, instance) { return arr; } - baseModule.__allocArray = __allocArray; + extendedExports.__allocArray = __allocArray; /** Gets a live view on an array's values in the module's memory. Infers the array type from RTTI. */ function __getArrayView(arr) { @@ -190,7 +190,7 @@ function postInstantiate(baseModule, instance) { const info = getInfo(id); if (!(info & ARRAYBUFFERVIEW)) throw Error("not an array: " + id); const align = getValueAlign(info); - var buf = U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2]; + let buf = U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2]; const length = info & ARRAY ? U32[arr + ARRAY_LENGTH_OFFSET >>> 2] : U32[buf + SIZE_OFFSET >>> 2] >>> align; @@ -198,7 +198,7 @@ function postInstantiate(baseModule, instance) { .subarray(buf >>>= align, buf + length); } - baseModule.__getArrayView = __getArrayView; + extendedExports.__getArrayView = __getArrayView; /** Copies an array's values from the module's memory. Infers the array type from RTTI. */ function __getArray(arr) { @@ -209,7 +209,7 @@ function postInstantiate(baseModule, instance) { return out; } - baseModule.__getArray = __getArray; + extendedExports.__getArray = __getArray; /** Copies an ArrayBuffer's value from the module's memory. */ function __getArrayBuffer(ptr) { @@ -218,7 +218,7 @@ function postInstantiate(baseModule, instance) { return buffer.slice(ptr, ptr + length); } - baseModule.__getArrayBuffer = __getArrayBuffer; + extendedExports.__getArrayBuffer = __getArrayBuffer; /** Copies a typed array's values from the module's memory. */ function getTypedArray(Type, alignLog2, ptr) { @@ -233,35 +233,35 @@ function postInstantiate(baseModule, instance) { return new Type(buffer, bufPtr, U32[bufPtr + SIZE_OFFSET >>> 2] >>> alignLog2); } - baseModule.__getInt8Array = getTypedArray.bind(null, Int8Array, 0); - baseModule.__getInt8ArrayView = getTypedArrayView.bind(null, Int8Array, 0); - baseModule.__getUint8Array = getTypedArray.bind(null, Uint8Array, 0); - baseModule.__getUint8ArrayView = getTypedArrayView.bind(null, Uint8Array, 0); - baseModule.__getUint8ClampedArray = getTypedArray.bind(null, Uint8ClampedArray, 0); - baseModule.__getUint8ClampedArrayView = getTypedArrayView.bind(null, Uint8ClampedArray, 0); - baseModule.__getInt16Array = getTypedArray.bind(null, Int16Array, 1); - baseModule.__getInt16ArrayView = getTypedArrayView.bind(null, Int16Array, 1); - baseModule.__getUint16Array = getTypedArray.bind(null, Uint16Array, 1); - baseModule.__getUint16ArrayView = getTypedArrayView.bind(null, Uint16Array, 1); - baseModule.__getInt32Array = getTypedArray.bind(null, Int32Array, 2); - baseModule.__getInt32ArrayView = getTypedArrayView.bind(null, Int32Array, 2); - baseModule.__getUint32Array = getTypedArray.bind(null, Uint32Array, 2); - baseModule.__getUint32ArrayView = getTypedArrayView.bind(null, Uint32Array, 2); + extendedExports.__getInt8Array = getTypedArray.bind(null, Int8Array, 0); + extendedExports.__getInt8ArrayView = getTypedArrayView.bind(null, Int8Array, 0); + extendedExports.__getUint8Array = getTypedArray.bind(null, Uint8Array, 0); + extendedExports.__getUint8ArrayView = getTypedArrayView.bind(null, Uint8Array, 0); + extendedExports.__getUint8ClampedArray = getTypedArray.bind(null, Uint8ClampedArray, 0); + extendedExports.__getUint8ClampedArrayView = getTypedArrayView.bind(null, Uint8ClampedArray, 0); + extendedExports.__getInt16Array = getTypedArray.bind(null, Int16Array, 1); + extendedExports.__getInt16ArrayView = getTypedArrayView.bind(null, Int16Array, 1); + extendedExports.__getUint16Array = getTypedArray.bind(null, Uint16Array, 1); + extendedExports.__getUint16ArrayView = getTypedArrayView.bind(null, Uint16Array, 1); + extendedExports.__getInt32Array = getTypedArray.bind(null, Int32Array, 2); + extendedExports.__getInt32ArrayView = getTypedArrayView.bind(null, Int32Array, 2); + extendedExports.__getUint32Array = getTypedArray.bind(null, Uint32Array, 2); + extendedExports.__getUint32ArrayView = getTypedArrayView.bind(null, Uint32Array, 2); if (BIGINT) { - baseModule.__getInt64Array = getTypedArray.bind(null, BigInt64Array, 3); - baseModule.__getInt64ArrayView = getTypedArrayView.bind(null, BigInt64Array, 3); - baseModule.__getUint64Array = getTypedArray.bind(null, BigUint64Array, 3); - baseModule.__getUint64ArrayView = getTypedArrayView.bind(null, BigUint64Array, 3); + extendedExports.__getInt64Array = getTypedArray.bind(null, BigInt64Array, 3); + extendedExports.__getInt64ArrayView = getTypedArrayView.bind(null, BigInt64Array, 3); + extendedExports.__getUint64Array = getTypedArray.bind(null, BigUint64Array, 3); + extendedExports.__getUint64ArrayView = getTypedArrayView.bind(null, BigUint64Array, 3); } - baseModule.__getFloat32Array = getTypedArray.bind(null, Float32Array, 2); - baseModule.__getFloat32ArrayView = getTypedArrayView.bind(null, Float32Array, 2); - baseModule.__getFloat64Array = getTypedArray.bind(null, Float64Array, 3); - baseModule.__getFloat64ArrayView = getTypedArrayView.bind(null, Float64Array, 3); + extendedExports.__getFloat32Array = getTypedArray.bind(null, Float32Array, 2); + extendedExports.__getFloat32ArrayView = getTypedArrayView.bind(null, Float32Array, 2); + extendedExports.__getFloat64Array = getTypedArray.bind(null, Float64Array, 3); + extendedExports.__getFloat64ArrayView = getTypedArrayView.bind(null, Float64Array, 3); /** 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); - var id = U32[(ptr + ID_OFFSET) >>> 2]; + let id = U32[(ptr + ID_OFFSET) >>> 2]; if (id <= U32[rttiBase >>> 2]) { do if (id == baseId) return true; while (id = getBase(id)); @@ -269,53 +269,49 @@ function postInstantiate(baseModule, instance) { return false; } - baseModule.__instanceof = __instanceof; + extendedExports.__instanceof = __instanceof; - // Pull basic exports to baseModule so code in preInstantiate can use them - baseModule.memory = baseModule.memory || memory; - baseModule.table = baseModule.table || table; + // Pull basic exports to extendedExports so code in preInstantiate can use them + extendedExports.memory = extendedExports.memory || memory; + extendedExports.table = extendedExports.table || table; // Demangle exports and provide the usual utility on the prototype - return demangle(rawExports, baseModule); + return demangle(exports, extendedExports); } -function isResponse(o) { - return typeof Response !== "undefined" && o instanceof Response; +function isResponse(src) { + return typeof Response !== "undefined" && src instanceof Response; +} + +function isModule(src) { + return src instanceof WebAssembly.Module; } /** Asynchronously instantiates an AssemblyScript module from anything that can be instantiated. */ -async function instantiate(source, imports) { +async function instantiate(source, imports = {}) { if (isResponse(source = await source)) return instantiateStreaming(source, imports); - return postInstantiate( - preInstantiate(imports || (imports = {})), - await WebAssembly.instantiate( - source instanceof WebAssembly.Module - ? source - : await WebAssembly.compile(source), - imports - ) - ); + const module = isModule(source) ? source : await WebAssembly.compile(source); + const extended = preInstantiate(imports); + const instance = await WebAssembly.instantiate(module, imports); + const exports = postInstantiate(extended, instance); + return { module, instance, exports }; } exports.instantiate = instantiate; /** Synchronously instantiates an AssemblyScript module from a WebAssembly.Module or binary buffer. */ -function instantiateSync(source, imports) { - return postInstantiate( - preInstantiate(imports || (imports = {})), - new WebAssembly.Instance( - source instanceof WebAssembly.Module - ? source - : new WebAssembly.Module(source), - imports - ) - ) +function instantiateSync(source, imports = {}) { + const module = isModule(source) ? source : new WebAssembly.Module(source); + const extended = preInstantiate(imports); + const instance = new WebAssembly.Instance(module, imports); + const exports = postInstantiate(extended, instance); + return { module, instance, exports }; } exports.instantiateSync = instantiateSync; /** Asynchronously instantiates an AssemblyScript module from a response, i.e. as obtained by `fetch`. */ -async function instantiateStreaming(source, imports) { +async function instantiateStreaming(source, imports = {}) { if (!WebAssembly.instantiateStreaming) { return instantiate( isResponse(source = await source) @@ -324,25 +320,25 @@ async function instantiateStreaming(source, imports) { imports ); } - return postInstantiate( - preInstantiate(imports || (imports = {})), - (await WebAssembly.instantiateStreaming(source, imports)).instance - ); + const extended = preInstantiate(imports); + const result = await WebAssembly.instantiateStreaming(source, imports); + const exports = postInstantiate(extended, result.instance); + return { ...result, exports }; } exports.instantiateStreaming = instantiateStreaming; /** Demangles an AssemblyScript module's exports to a friendly object structure. */ -function demangle(exports, baseModule) { - var module = baseModule ? Object.create(baseModule) : {}; - var setArgumentsLength = exports["__argumentsLength"] - ? function(length) { exports["__argumentsLength"].value = length; } - : exports["__setArgumentsLength"] || exports["__setargc"] || function() {}; +function demangle(exports, extendedExports = {}) { + extendedExports = Object.create(extendedExports); + const setArgumentsLength = exports["__argumentsLength"] + ? length => { exports["__argumentsLength"].value = length; } + : exports["__setArgumentsLength"] || exports["__setargc"] || (() => {}); for (let internalName in exports) { if (!Object.prototype.hasOwnProperty.call(exports, internalName)) continue; const elem = exports[internalName]; let parts = internalName.split("."); - let curr = module; + let curr = extendedExports; while (parts.length > 1) { let part = parts.shift(); if (!Object.prototype.hasOwnProperty.call(curr, part)) curr[part] = {}; @@ -351,10 +347,10 @@ function demangle(exports, baseModule) { let name = parts[0]; let hash = name.indexOf("#"); if (hash >= 0) { - let className = name.substring(0, hash); - let classElem = curr[className]; + const className = name.substring(0, hash); + const classElem = curr[className]; if (typeof classElem === "undefined" || !classElem.prototype) { - let ctor = function(...args) { + const ctor = function(...args) { return ctor.wrap(ctor.prototype.constructor(0, ...args)); }; ctor.prototype = { @@ -414,7 +410,7 @@ function demangle(exports, baseModule) { } } } - return module; + return extendedExports; } exports.demangle = demangle; diff --git a/lib/loader/tests/index.js b/lib/loader/tests/index.js index bef4129e5a..8dee745204 100644 --- a/lib/loader/tests/index.js +++ b/lib/loader/tests/index.js @@ -12,44 +12,45 @@ testInstantiate("legacy.wasm"); function test(file) { var buffer = fs.readFileSync(__dirname + "/build/" + file); - var module = loader.instantiateSync(buffer, {}); + var result = loader.instantiateSync(buffer, {}); + const exports = result.exports; - console.log(inspect(module, true, 100, true)); + console.log(inspect(exports, true, 100, true)); // should export memory - assert(module.memory instanceof WebAssembly.Memory); - assert(typeof module.memory.copy === "function"); + assert(exports.memory instanceof WebAssembly.Memory); + assert(typeof exports.memory.copy === "function"); // should be able to get an exported string - assert.strictEqual(module.__getString(module.COLOR), "red"); + assert.strictEqual(exports.__getString(exports.COLOR), "red"); // should be able to allocate and work with a new string { let str = "Hello world!𤭢"; - let ref = module.__retain(module.__allocString(str)); - assert.strictEqual(module.__getString(ref), str); - assert.strictEqual(module.strlen(ref), str.length); - module.__release(ref); + let ref = exports.__retain(exports.__allocString(str)); + assert.strictEqual(exports.__getString(ref), str); + assert.strictEqual(exports.strlen(ref), str.length); + exports.__release(ref); } // should be able to allocate a typed array { var arr = [1, 2, 3, 4, 5, 0x80000000 | 0]; - let ref = module.__retain(module.__allocArray(module.INT32ARRAY_ID, arr)); - assert(module.__instanceof(ref, module.INT32ARRAY_ID)); + let ref = exports.__retain(exports.__allocArray(exports.INT32ARRAY_ID, arr)); + assert(exports.__instanceof(ref, exports.INT32ARRAY_ID)); // should be able to get the values of an array - assert.deepEqual(module.__getArray(ref), arr); + assert.deepEqual(exports.__getArray(ref), arr); // should be able to get a view on an array - assert.deepEqual(module.__getArrayView(ref), new Int32Array(arr)); + assert.deepEqual(exports.__getArrayView(ref), new Int32Array(arr)); // should be able to sum up its values - assert.strictEqual(module.sum(ref), arr.reduce((a, b) => (a + b) | 0, 0) | 0); + assert.strictEqual(exports.sum(ref), arr.reduce((a, b) => (a + b) | 0, 0) | 0); // should be able to release no longer needed references - module.__release(ref); - try { module.__release(ref); assert(false); } catch (e) {}; + exports.__release(ref); + try { exports.__release(ref); assert(false); } catch (e) {}; } /* @@ -80,62 +81,62 @@ function test(file) { // should be able to distinguish between signed and unsigned { let arr = new Uint8Array([0, 255, 127]); - let ref = module.__retain(module.__allocArray(module.UINT8ARRAY_ID, arr)); - assert(module.__instanceof(ref, module.UINT8ARRAY_ID)); - assert.deepEqual(module.__getUint8Array(ref), arr); - module.__release(ref); - try { module.__release(ref); assert(false); } catch (e) {}; + let ref = exports.__retain(exports.__allocArray(exports.UINT8ARRAY_ID, arr)); + assert(exports.__instanceof(ref, exports.UINT8ARRAY_ID)); + assert.deepEqual(exports.__getUint8Array(ref), arr); + exports.__release(ref); + try { exports.__release(ref); assert(false); } catch (e) {}; } // should be able to distinguish between signed and unsigned { let arr = new Int16Array([0, 0xFFFF, -0x00FF]); - let ref = module.__retain(module.__allocArray(module.INT16ARRAY_ID, arr)); - assert(module.__instanceof(ref, module.INT16ARRAY_ID)); - assert.deepEqual(module.__getInt16Array(ref), arr); - module.__release(ref); - try { module.__release(ref); assert(false); } catch (e) {}; + let ref = exports.__retain(exports.__allocArray(exports.INT16ARRAY_ID, arr)); + assert(exports.__instanceof(ref, exports.INT16ARRAY_ID)); + assert.deepEqual(exports.__getInt16Array(ref), arr); + exports.__release(ref); + try { exports.__release(ref); assert(false); } catch (e) {}; } // should be able to distinguish between signed and unsigned { let arr = [1, -1 >>> 0, 0x80000000]; - let ref = module.__retain(module.__allocArray(module.UINT32ARRAY_ID, arr)); - assert(module.__instanceof(ref, module.UINT32ARRAY_ID)); - assert.deepEqual(module.__getUint32Array(ref), new Uint32Array(arr)); - assert.deepEqual(module.__getUint32ArrayView(ref), new Uint32Array(arr)); - assert.deepEqual(module.__getArray(ref), arr); - module.__release(ref); - try { module.__release(ref); assert(false); } catch (e) {}; + let ref = exports.__retain(exports.__allocArray(exports.UINT32ARRAY_ID, arr)); + assert(exports.__instanceof(ref, exports.UINT32ARRAY_ID)); + assert.deepEqual(exports.__getUint32Array(ref), new Uint32Array(arr)); + assert.deepEqual(exports.__getUint32ArrayView(ref), new Uint32Array(arr)); + assert.deepEqual(exports.__getArray(ref), arr); + exports.__release(ref); + try { exports.__release(ref); assert(false); } catch (e) {}; } // should be able to distinguish between integer and float { let arr = [0.0, 1.5, 2.5]; - let ref = module.__retain(module.__allocArray(module.FLOAT32ARRAY_ID, arr)); - assert(module.__instanceof(ref, module.FLOAT32ARRAY_ID)); - assert.deepEqual(module.__getFloat32Array(ref), new Float32Array(arr)); - assert.deepEqual(module.__getFloat32ArrayView(ref), new Float32Array(arr)); - assert.deepEqual(module.__getArray(ref), arr); - module.__release(ref); - try { module.__release(ref); assert(false); } catch (e) {}; + let ref = exports.__retain(exports.__allocArray(exports.FLOAT32ARRAY_ID, arr)); + assert(exports.__instanceof(ref, exports.FLOAT32ARRAY_ID)); + assert.deepEqual(exports.__getFloat32Array(ref), new Float32Array(arr)); + assert.deepEqual(exports.__getFloat32ArrayView(ref), new Float32Array(arr)); + assert.deepEqual(exports.__getArray(ref), arr); + exports.__release(ref); + try { exports.__release(ref); assert(false); } catch (e) {}; } // should be able to work with normal arrays { let arr = [1, 2, 3, 4, 5]; - let ref = module.__retain(module.__allocArray(module.ARRAYI32_ID, arr)); - assert(module.__instanceof(ref, module.ARRAYI32_ID)); - module.changeLength(ref, 3); - assert.deepEqual(module.__getArray(ref), [1, 2, 3]); - module.__release(ref); - try { module.__release(ref); assert(false); } catch (e) {}; + let ref = exports.__retain(exports.__allocArray(exports.ARRAYI32_ID, arr)); + assert(exports.__instanceof(ref, exports.ARRAYI32_ID)); + exports.changeLength(ref, 3); + assert.deepEqual(exports.__getArray(ref), [1, 2, 3]); + exports.__release(ref); + try { exports.__release(ref); assert(false); } catch (e) {}; } // should be able to correctly call a function with variable arguments - assert.strictEqual(module.varadd(), 3); - assert.strictEqual(module.varadd(2, 3), 5); - assert.strictEqual(module.varadd(2), 4); + assert.strictEqual(exports.varadd(), 3); + assert.strictEqual(exports.varadd(2, 3), 5); + assert.strictEqual(exports.varadd(2), 4); // TBD: table is no more exported by default to allow more optimizations @@ -150,67 +151,75 @@ function test(file) { // assert.strictEqual(module.calladd(ref, 2, 3), 5); // should be able to use a class - var car = new module.Car(5); + var car = new exports.Car(5); assert.strictEqual(car.numDoors, 5); assert.strictEqual(car.isDoorsOpen, 0); car.openDoors(); assert.strictEqual(car.isDoorsOpen, 1); car.closeDoors(); assert.strictEqual(car.isDoorsOpen, 0); - module.__release(car); // uses Car.prototype.valueOf to obtain `thisPtr` + exports.__release(car); // uses Car.prototype.valueOf to obtain `thisPtr` // should be able to use trace - module.dotrace(42); + exports.dotrace(42); // should be able to mutate an array in place using getArrayView { - let ptr = module.__retain(module.__allocArray(module.FLOAT32ARRAY_ID, [1, 2, 3])); - let view = module.__getArrayView(ptr); + let ptr = exports.__retain(exports.__allocArray(exports.FLOAT32ARRAY_ID, [1, 2, 3])); + let view = exports.__getArrayView(ptr); assert.deepEqual(view, new Float32Array([1, 2, 3])); - module.modifyFloat32Array(ptr, 0, 4); + exports.modifyFloat32Array(ptr, 0, 4); assert.deepEqual(view, new Float32Array([4, 2, 3])); - module.__release(ptr); + exports.__release(ptr); } // should be able to mutate an array in place using getFloat32Array { - let ptr = module.newFloat32Array(3); // returns are pre-retained - let view = module.__getFloat32ArrayView(ptr); - let arr = module.__getFloat32Array(ptr); + let ptr = exports.newFloat32Array(3); // returns are pre-retained + let view = exports.__getFloat32ArrayView(ptr); + let arr = exports.__getFloat32Array(ptr); assert.deepEqual(view, new Float32Array([0, 0, 0])); assert.deepEqual(arr, new Float32Array([0, 0, 0])); - module.modifyFloat32Array(ptr, 0, 3); - module.modifyFloat32Array(ptr, 1, 2); - module.modifyFloat32Array(ptr, 2, 1); + exports.modifyFloat32Array(ptr, 0, 3); + exports.modifyFloat32Array(ptr, 1, 2); + exports.modifyFloat32Array(ptr, 2, 1); assert.deepEqual(view, new Float32Array([3, 2, 1])); assert.deepEqual(arr, new Float32Array([0, 0, 0])); - module.__release(ptr); + exports.__release(ptr); } } function testInstantiate(file) { // should be able to instantiate from a buffer (async () => { - const module = await loader.instantiate(fs.readFileSync(__dirname + "/build/" + file), {}); - assert(module.memory); + const { exports, instance, module } = await loader.instantiate(fs.readFileSync(__dirname + "/build/" + file), {}); + assert(exports.memory); + assert(instance && instance instanceof WebAssembly.Instance); + assert(module && module instanceof WebAssembly.Module); })(); // should be able to instantiate from a wasm module (async () => { const wasmModule = new WebAssembly.Module(fs.readFileSync(__dirname + "/build/" + file)); - const module = await loader.instantiate(wasmModule, {}); - assert(module.memory); + const { exports, instance, module } = await loader.instantiate(wasmModule, {}); + assert(exports.memory); + assert(instance && instance instanceof WebAssembly.Instance); + assert(module && module instanceof WebAssembly.Module); })(); // should be able to instantiate from a promise yielding a buffer (async () => { - const module = await loader.instantiate(fs.promises.readFile(__dirname + "/build/" + file), {}); - assert(module.memory); + const { exports, instance, module } = await loader.instantiate(fs.promises.readFile(__dirname + "/build/" + file), {}); + assert(exports.memory); + assert(instance && instance instanceof WebAssembly.Instance); + assert(module && module instanceof WebAssembly.Module); })(); // should be able to mimic instantiateStreaming under node (for now) (async () => { - const module = await loader.instantiateStreaming(fs.promises.readFile(__dirname + "/build/" + file), {}); - assert(module.memory); + const { exports, instance, module } = await loader.instantiateStreaming(fs.promises.readFile(__dirname + "/build/" + file), {}); + assert(exports.memory); + assert(instance && instance instanceof WebAssembly.Instance); + assert(module && module instanceof WebAssembly.Module); })(); } \ No newline at end of file diff --git a/tests/bootstrap/index.ts b/tests/bootstrap/index.ts index 60828f9610..bafb9ff1b7 100644 --- a/tests/bootstrap/index.ts +++ b/tests/bootstrap/index.ts @@ -6,17 +6,20 @@ import AssemblyScript from "../../out/assemblyscript"; async function test(build: string): Promise { await binaryen.ready; - const assemblyscript = await loader.instantiate(fs.promises.readFile(__dirname + "/../../out/assemblyscript." + build + ".wasm"), { binaryen }); - console.log(util.inspect(assemblyscript, true)); - const optionsPtr = assemblyscript.newOptions(); - const programPtr = assemblyscript.newProgram(optionsPtr); - const textPtr = assemblyscript.__allocString("export function add(a: i32, b: i32): i32 { return a + b; }\n"); - const pathPtr = assemblyscript.__allocString("index.ts"); - assemblyscript.parse(programPtr, textPtr, pathPtr, true); - var nextFilePtr = assemblyscript.nextFile(programPtr); + const { exports: asc } = await loader.instantiate( + fs.promises.readFile(`${ __dirname }/../../out/assemblyscript.${ build }.wasm`), + { binaryen } + ); + console.log(util.inspect(asc, true)); + const optionsPtr = asc.newOptions(); + const programPtr = asc.newProgram(optionsPtr); + const textPtr = asc.__allocString("export function add(a: i32, b: i32): i32 { return a + b; }\n"); + const pathPtr = asc.__allocString("index.ts"); + asc.parse(programPtr, textPtr, pathPtr, true); + var nextFilePtr = asc.nextFile(programPtr); while (nextFilePtr) { - console.log("nextFile: " + assemblyscript.__getString(nextFilePtr)); - nextFilePtr = assemblyscript.nextFile(programPtr); + console.log("nextFile: " + asc.__getString(nextFilePtr)); + nextFilePtr = asc.nextFile(programPtr); } // assemblyscript.compile(programPtr); // ^ abort: missing ArrayBuffer at src/program.ts:1015:18