diff --git a/lib/loader/index.js b/lib/loader/index.js index aa32b1cc..b46473ee 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -1,11 +1,15 @@ "use strict"; -/** Size of the runtime header, in bytes. */ -const HEADER_SIZE = 16; -/** Runtime header offset of `classId`. */ -const CLASSID_OFFSET = -HEADER_SIZE; -/** Runtime header offset of `payloadLength`. */ -const PAYLOADLENGTH_OFFSET = -HEADER_SIZE + 4; +/** Relative header `id` offset. */ +const ID_OFFSET = -8; +/** Relative header `size` offset. */ +const SIZE_OFFSET = -4; + +/** Unique runtime id of an `ArrayBuffer`. */ +const ARRAYBUFFER_ID = 0; +/** Unique runtime id of a `String`. */ +const STRING_ID = 1; + /** Whether BigInt arrays are supported. */ const SUPPORTS_BIGINT = typeof BigUint64Array !== "undefined"; /** Unique symbol for memoized 'this'. */ @@ -13,19 +17,18 @@ const THIS = Symbol(); /** Gets a string from an U32 and an U16 view on a memory. */ function getStringImpl(U32, U16, ptr) { - var size32 = U32[(ptr + PAYLOADLENGTH_OFFSET) >>> 2]; - var offset16 = ptr >>> 1; - var remain32 = size32; + var length = U32[(ptr + SIZE_OFFSET) >>> 2] >>> 1; + var offset = ptr >>> 1; var parts = []; const chunkSize = 1024; - while (remain32 > chunkSize) { - let last = U16[offset16 + chunkSize - 1]; + while (length > chunkSize) { + let last = U16[offset + chunkSize - 1]; let size = last >= 0xD800 && last < 0xDC00 ? chunkSize - 1 : chunkSize; - let part = U16.subarray(offset16, offset16 += size); + let part = U16.subarray(offset, offset += size); parts.push(String.fromCharCode.apply(String, part)); - remain32 -= size; + length -= size; } - return parts.join("") + String.fromCharCode.apply(String, U16.subarray(offset16, offset16 + remain32)); + return parts.join("") + String.fromCharCode.apply(String, U16.subarray(offset, offset + length)); } /** Prepares the base module prior to instantiation. */ @@ -58,11 +61,11 @@ function preInstantiate(imports) { function postInstantiate(baseModule, instance) { var rawExports = instance.exports; var memory = rawExports.memory; - var memory_allocate = rawExports["memory.allocate"]; + var alloc = rawExports["__alloc"]; + var free = rawExports["__free"]; + var setargc = rawExports["__setargc"] || function() {}; var memory_fill = rawExports["memory.fill"]; - var memory_free = rawExports["memory.free"]; var table = rawExports.table; - var setargc = rawExports["$.setArgc"] || function() {}; // Provide views for all sorts of basic values var buffer, I8, U8, I16, U16, I32, U32, F32, F64, I64, U64; @@ -90,12 +93,10 @@ function postInstantiate(baseModule, instance) { /** Allocates a new string in the module's memory and returns its pointer. */ function newString(str) { - var dataLength = str.length; - var ptr = memory_allocate(4 + (dataLength << 1)); - var dataOffset = (4 + ptr) >>> 1; + var length = str.length; + var ptr = alloc(length << 1, STRING_ID); checkMem(); - U32[ptr >>> 2] = dataLength; - for (let i = 0; i < dataLength; ++i) U16[dataOffset + i] = str.charCodeAt(i); + for (let i = 0, j = ptr >>> 1; i < length; ++i) U16[j + i] = str.charCodeAt(i); return ptr; } @@ -109,88 +110,88 @@ function postInstantiate(baseModule, instance) { baseModule.getString = getString; - function computeBufferSize(byteLength) { - const HEADER_SIZE = 8; - return 1 << (32 - Math.clz32(byteLength + HEADER_SIZE - 1)); - } + // function computeBufferSize(byteLength) { + // const HEADER_SIZE = 8; + // return 1 << (32 - Math.clz32(byteLength + HEADER_SIZE - 1)); + // } - /** Creates a new typed array in the module's memory and returns its pointer. */ - function newArray(view, length, unsafe) { - var ctor = view.constructor; - if (ctor === Function) { // TypedArray constructor created in memory - ctor = view; - view = null; - } else { // TypedArray instance copied into memory - if (length === undefined) length = view.length; - } - var elementSize = ctor.BYTES_PER_ELEMENT; - if (!elementSize) throw Error("not a typed array"); - var byteLength = elementSize * length; - var ptr = memory_allocate(12); // TypedArray header - var buf = memory_allocate(computeBufferSize(byteLength)); // ArrayBuffer - checkMem(); - U32[ ptr >>> 2] = buf; // .buffer - U32[(ptr + 4) >>> 2] = 0; // .byteOffset - U32[(ptr + 8) >>> 2] = byteLength; // .byteLength - U32[ buf >>> 2] = byteLength; // .byteLength - U32[(buf + 4) >>> 2] = 0; // 0 - if (view) { - new ctor(buffer, buf + 8, length).set(view); - if (view.length < length && !unsafe) { - let setLength = elementSize * view.length; - memory_fill(buf + 8 + setLength, 0, byteLength - setLength); - } - } else if (!unsafe) { - memory_fill(buf + 8, 0, byteLength); - } - return ptr; - } + // /** Creates a new typed array in the module's memory and returns its pointer. */ + // function newArray(view, length, unsafe) { + // var ctor = view.constructor; + // if (ctor === Function) { // TypedArray constructor created in memory + // ctor = view; + // view = null; + // } else { // TypedArray instance copied into memory + // if (length === undefined) length = view.length; + // } + // var elementSize = ctor.BYTES_PER_ELEMENT; + // if (!elementSize) throw Error("not a typed array"); + // var byteLength = elementSize * length; + // var ptr = alloc(12); // TypedArray header + // var buf = alloc(computeBufferSize(byteLength)); // ArrayBuffer + // checkMem(); + // U32[ ptr >>> 2] = buf; // .buffer + // U32[(ptr + 4) >>> 2] = 0; // .byteOffset + // U32[(ptr + 8) >>> 2] = byteLength; // .byteLength + // U32[ buf >>> 2] = byteLength; // .byteLength + // U32[(buf + 4) >>> 2] = 0; // 0 + // if (view) { + // new ctor(buffer, buf + 8, length).set(view); + // if (view.length < length && !unsafe) { + // let setLength = elementSize * view.length; + // memory_fill(buf + 8 + setLength, 0, byteLength - setLength); + // } + // } else if (!unsafe) { + // memory_fill(buf + 8, 0, byteLength); + // } + // return ptr; + // } - baseModule.newArray = newArray; + // baseModule.newArray = newArray; - /** Gets a view on a typed array in the module's memory by its pointer. */ - function getArray(ctor, ptr) { - var elementSize = ctor.BYTES_PER_ELEMENT; - if (!elementSize) throw Error("not a typed array"); - checkMem(); - var buf = U32[ ptr >>> 2]; - var byteOffset = U32[(ptr + 4) >>> 2]; - var byteLength = U32[(ptr + 8) >>> 2]; - return new ctor(buffer, buf + 8 + byteOffset, (byteLength - byteOffset) / elementSize); - } + // /** Gets a view on a typed array in the module's memory by its pointer. */ + // function getArray(ctor, ptr) { + // var elementSize = ctor.BYTES_PER_ELEMENT; + // if (!elementSize) throw Error("not a typed array"); + // checkMem(); + // var buf = U32[ ptr >>> 2]; + // var byteOffset = U32[(ptr + 4) >>> 2]; + // var byteLength = U32[(ptr + 8) >>> 2]; + // return new ctor(buffer, buf + 8 + byteOffset, (byteLength - byteOffset) / elementSize); + // } - baseModule.getArray = getArray; + // baseModule.getArray = getArray; - /** Frees a typed array in the module's memory. Must not be accessed anymore afterwards. */ - function freeArray(ptr) { - checkMem(); - var buf = U32[ptr >>> 2]; - memory_free(buf); - memory_free(ptr); - } + // /** Frees a typed array in the module's memory. Must not be accessed anymore afterwards. */ + // function freeArray(ptr) { + // checkMem(); + // var buf = U32[ptr >>> 2]; + // free(buf); + // free(ptr); + // } - baseModule.freeArray = freeArray; + // baseModule.freeArray = freeArray; - /** - * Creates a new function in the module's table and returns its pointer. Note that only actual - * WebAssembly functions, i.e. as exported by the module, are supported. - */ - function newFunction(fn) { - if (typeof fn.original === "function") fn = fn.original; - var index = table.length; - table.grow(1); - table.set(index, fn); - return index; - } + // /** + // * Creates a new function in the module's table and returns its pointer. Note that only actual + // * WebAssembly functions, i.e. as exported by the module, are supported. + // */ + // function newFunction(fn) { + // if (typeof fn.original === "function") fn = fn.original; + // var index = table.length; + // table.grow(1); + // table.set(index, fn); + // return index; + // } - baseModule.newFunction = newFunction; + // baseModule.newFunction = newFunction; - /** Gets a function by its pointer. */ - function getFunction(ptr) { - return wrapFunction(table.get(ptr), setargc); - } + // /** Gets a function by its pointer. */ + // function getFunction(ptr) { + // return wrapFunction(table.get(ptr), setargc); + // } - baseModule.getFunction = getFunction; + // baseModule.getFunction = getFunction; // Pull basic exports to baseModule so code in preInstantiate can use them baseModule.memory = baseModule.memory || memory; @@ -253,7 +254,7 @@ 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 setargc = exports[".setargc"] || function() {}; + var setargc = exports["__setargc"] || function() {}; function hasOwnProperty(elem, prop) { return Object.prototype.hasOwnProperty.call(elem, prop); } diff --git a/lib/loader/tests/assembly/index.ts b/lib/loader/tests/assembly/index.ts index 1c60c327..770be909 100644 --- a/lib/loader/tests/assembly/index.ts +++ b/lib/loader/tests/assembly/index.ts @@ -1,5 +1,3 @@ -import "allocator/tlsf"; - export { memory }; export const COLOR: string = "red"; @@ -39,10 +37,6 @@ export class Car { this.doorsOpen = false; return true; } - - dispose(): void { - memory.free(changetype(this)); - } } export function sum(arr: Int32Array): i32 { diff --git a/lib/loader/tests/build/untouched.wasm b/lib/loader/tests/build/untouched.wasm index 656568df..5bdfc74d 100644 Binary files a/lib/loader/tests/build/untouched.wasm and b/lib/loader/tests/build/untouched.wasm differ diff --git a/lib/loader/tests/index.js b/lib/loader/tests/index.js index 133dda77..3b0ce510 100644 --- a/lib/loader/tests/index.js +++ b/lib/loader/tests/index.js @@ -21,7 +21,7 @@ assert(proto.F64 instanceof Float64Array); // should export memory assert(module.memory instanceof WebAssembly.Memory); -assert(typeof module.memory.free === "function"); +assert(typeof module.memory.copy === "function"); // should be able to get an exported string assert.strictEqual(module.getString(module.COLOR), "red"); @@ -33,17 +33,17 @@ assert.strictEqual(module.getString(ptr), str); assert.strictEqual(module.strlen(ptr), str.length); // should be able to allocate a typed array and sum up its values -var arr = [1, 2, 3, 4, 5, 0x7fffffff]; -ptr = module.newArray(new Int32Array(arr)); -assert.strictEqual(module.sum(ptr), arr.reduce((a, b) => a + b, 0) | 0); +// var arr = [1, 2, 3, 4, 5, 0x7fffffff]; +// ptr = module.newArray(new Int32Array(arr)); +// assert.strictEqual(module.sum(ptr), arr.reduce((a, b) => a + b, 0) | 0); // should be able to get a view on an internal typed array -assert.deepEqual(module.getArray(Int32Array, ptr), arr); +// assert.deepEqual(module.getArray(Int32Array, ptr), arr); // should be able to free and reuse the space of an internal typed array -module.freeArray(ptr); -var ptr2 = module.newArray(new Int32Array(arr)); -assert.strictEqual(ptr, ptr2); +// module.freeArray(ptr); +// var ptr2 = module.newArray(new Int32Array(arr)); +// assert.strictEqual(ptr, ptr2); // should be able to just call a function with variable arguments assert.strictEqual(module.varadd(), 3); @@ -51,14 +51,14 @@ assert.strictEqual(module.varadd(2, 3), 5); assert.strictEqual(module.varadd(2), 4); // should be able to get a function from the table and just call it with variable arguments -var fn = module.getFunction(module.varadd_ptr); -assert.strictEqual(fn(), 3); -assert.strictEqual(fn(2, 3), 5); -assert.strictEqual(fn(2), 4); +// var fn = module.getFunction(module.varadd_ptr); +// assert.strictEqual(fn(), 3); +// assert.strictEqual(fn(2, 3), 5); +// assert.strictEqual(fn(2), 4); // should be able to create a new function and call it from WASM -ptr = module.newFunction(module.varadd); -assert.strictEqual(module.calladd(ptr, 2, 3), 5); +// ptr = module.newFunction(module.varadd); +// assert.strictEqual(module.calladd(ptr, 2, 3), 5); // should be able to use a class var car = new module.Car(5); @@ -70,4 +70,4 @@ car.closeDoors(); assert.strictEqual(car.isDoorsOpen, 0); // should be able to use trace -module.dotrace(42); \ No newline at end of file +module.dotrace(42); diff --git a/src/compiler.ts b/src/compiler.ts index f2575075..e4996703 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -6489,7 +6489,7 @@ export class Compiler extends DiagnosticEmitter { module.createGetLocal(0, NativeType.I32) ) ); - module.addFunctionExport(BuiltinSymbols.setargc, "$.setArgc"); + module.addFunctionExport(BuiltinSymbols.setargc, "__setargc"); } return BuiltinSymbols.setargc; } diff --git a/tests/compiler/exports.optimized.wat b/tests/compiler/exports.optimized.wat index 5c590e34..5f6568f7 100644 --- a/tests/compiler/exports.optimized.wat +++ b/tests/compiler/exports.optimized.wat @@ -20,7 +20,7 @@ (global $exports/vehicles.Car i32 (i32.const 4)) (export "memory" (memory $0)) (export "add" (func $exports/add)) - (export "$.setArgc" (func $~lib/setargc)) + (export "__setargc" (func $~lib/setargc)) (export "subOpt" (func $exports/subOpt|trampoline)) (export "math.sub" (func $exports/subOpt)) (export "Animal.CAT" (global $exports/Animal.CAT)) diff --git a/tests/compiler/exports.untouched.wat b/tests/compiler/exports.untouched.wat index c33c65f8..56fd0434 100644 --- a/tests/compiler/exports.untouched.wat +++ b/tests/compiler/exports.untouched.wat @@ -23,7 +23,7 @@ (global $exports/vehicles.Car i32 (i32.const 4)) (export "memory" (memory $0)) (export "add" (func $exports/add)) - (export "$.setArgc" (func $~lib/setargc)) + (export "__setargc" (func $~lib/setargc)) (export "subOpt" (func $exports/subOpt|trampoline)) (export "math.sub" (func $exports/math.sub)) (export "Animal.CAT" (global $exports/Animal.CAT))