monkey-patch loader

This commit is contained in:
dcode 2019-05-23 04:15:05 +02:00
parent 71ea61e099
commit 81c212b208
7 changed files with 114 additions and 119 deletions

View File

@ -1,11 +1,15 @@
"use strict"; "use strict";
/** Size of the runtime header, in bytes. */ /** Relative header `id` offset. */
const HEADER_SIZE = 16; const ID_OFFSET = -8;
/** Runtime header offset of `classId`. */ /** Relative header `size` offset. */
const CLASSID_OFFSET = -HEADER_SIZE; const SIZE_OFFSET = -4;
/** Runtime header offset of `payloadLength`. */
const PAYLOADLENGTH_OFFSET = -HEADER_SIZE + 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. */ /** Whether BigInt arrays are supported. */
const SUPPORTS_BIGINT = typeof BigUint64Array !== "undefined"; const SUPPORTS_BIGINT = typeof BigUint64Array !== "undefined";
/** Unique symbol for memoized 'this'. */ /** 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. */ /** Gets a string from an U32 and an U16 view on a memory. */
function getStringImpl(U32, U16, ptr) { function getStringImpl(U32, U16, ptr) {
var size32 = U32[(ptr + PAYLOADLENGTH_OFFSET) >>> 2]; var length = U32[(ptr + SIZE_OFFSET) >>> 2] >>> 1;
var offset16 = ptr >>> 1; var offset = ptr >>> 1;
var remain32 = size32;
var parts = []; var parts = [];
const chunkSize = 1024; const chunkSize = 1024;
while (remain32 > chunkSize) { while (length > chunkSize) {
let last = U16[offset16 + chunkSize - 1]; let last = U16[offset + chunkSize - 1];
let size = last >= 0xD800 && last < 0xDC00 ? chunkSize - 1 : chunkSize; 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)); 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. */ /** Prepares the base module prior to instantiation. */
@ -58,11 +61,11 @@ function preInstantiate(imports) {
function postInstantiate(baseModule, instance) { function postInstantiate(baseModule, instance) {
var rawExports = instance.exports; var rawExports = instance.exports;
var memory = rawExports.memory; 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_fill = rawExports["memory.fill"];
var memory_free = rawExports["memory.free"];
var table = rawExports.table; var table = rawExports.table;
var setargc = rawExports["$.setArgc"] || function() {};
// Provide views for all sorts of basic values // Provide views for all sorts of basic values
var buffer, I8, U8, I16, U16, I32, U32, F32, F64, I64, U64; 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. */ /** Allocates a new string in the module's memory and returns its pointer. */
function newString(str) { function newString(str) {
var dataLength = str.length; var length = str.length;
var ptr = memory_allocate(4 + (dataLength << 1)); var ptr = alloc(length << 1, STRING_ID);
var dataOffset = (4 + ptr) >>> 1;
checkMem(); checkMem();
U32[ptr >>> 2] = dataLength; for (let i = 0, j = ptr >>> 1; i < length; ++i) U16[j + i] = str.charCodeAt(i);
for (let i = 0; i < dataLength; ++i) U16[dataOffset + i] = str.charCodeAt(i);
return ptr; return ptr;
} }
@ -109,88 +110,88 @@ function postInstantiate(baseModule, instance) {
baseModule.getString = getString; baseModule.getString = getString;
function computeBufferSize(byteLength) { // function computeBufferSize(byteLength) {
const HEADER_SIZE = 8; // const HEADER_SIZE = 8;
return 1 << (32 - Math.clz32(byteLength + HEADER_SIZE - 1)); // return 1 << (32 - Math.clz32(byteLength + HEADER_SIZE - 1));
} // }
/** Creates a new typed array in the module's memory and returns its pointer. */ // /** Creates a new typed array in the module's memory and returns its pointer. */
function newArray(view, length, unsafe) { // function newArray(view, length, unsafe) {
var ctor = view.constructor; // var ctor = view.constructor;
if (ctor === Function) { // TypedArray constructor created in memory // if (ctor === Function) { // TypedArray constructor created in memory
ctor = view; // ctor = view;
view = null; // view = null;
} else { // TypedArray instance copied into memory // } else { // TypedArray instance copied into memory
if (length === undefined) length = view.length; // if (length === undefined) length = view.length;
} // }
var elementSize = ctor.BYTES_PER_ELEMENT; // var elementSize = ctor.BYTES_PER_ELEMENT;
if (!elementSize) throw Error("not a typed array"); // if (!elementSize) throw Error("not a typed array");
var byteLength = elementSize * length; // var byteLength = elementSize * length;
var ptr = memory_allocate(12); // TypedArray header // var ptr = alloc(12); // TypedArray header
var buf = memory_allocate(computeBufferSize(byteLength)); // ArrayBuffer // var buf = alloc(computeBufferSize(byteLength)); // ArrayBuffer
checkMem(); // checkMem();
U32[ ptr >>> 2] = buf; // .buffer // U32[ ptr >>> 2] = buf; // .buffer
U32[(ptr + 4) >>> 2] = 0; // .byteOffset // U32[(ptr + 4) >>> 2] = 0; // .byteOffset
U32[(ptr + 8) >>> 2] = byteLength; // .byteLength // U32[(ptr + 8) >>> 2] = byteLength; // .byteLength
U32[ buf >>> 2] = byteLength; // .byteLength // U32[ buf >>> 2] = byteLength; // .byteLength
U32[(buf + 4) >>> 2] = 0; // 0 // U32[(buf + 4) >>> 2] = 0; // 0
if (view) { // if (view) {
new ctor(buffer, buf + 8, length).set(view); // new ctor(buffer, buf + 8, length).set(view);
if (view.length < length && !unsafe) { // if (view.length < length && !unsafe) {
let setLength = elementSize * view.length; // let setLength = elementSize * view.length;
memory_fill(buf + 8 + setLength, 0, byteLength - setLength); // memory_fill(buf + 8 + setLength, 0, byteLength - setLength);
} // }
} else if (!unsafe) { // } else if (!unsafe) {
memory_fill(buf + 8, 0, byteLength); // memory_fill(buf + 8, 0, byteLength);
} // }
return ptr; // return ptr;
} // }
baseModule.newArray = newArray; // baseModule.newArray = newArray;
/** Gets a view on a typed array in the module's memory by its pointer. */ // /** Gets a view on a typed array in the module's memory by its pointer. */
function getArray(ctor, ptr) { // function getArray(ctor, ptr) {
var elementSize = ctor.BYTES_PER_ELEMENT; // var elementSize = ctor.BYTES_PER_ELEMENT;
if (!elementSize) throw Error("not a typed array"); // if (!elementSize) throw Error("not a typed array");
checkMem(); // checkMem();
var buf = U32[ ptr >>> 2]; // var buf = U32[ ptr >>> 2];
var byteOffset = U32[(ptr + 4) >>> 2]; // var byteOffset = U32[(ptr + 4) >>> 2];
var byteLength = U32[(ptr + 8) >>> 2]; // var byteLength = U32[(ptr + 8) >>> 2];
return new ctor(buffer, buf + 8 + byteOffset, (byteLength - byteOffset) / elementSize); // 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. */ // /** Frees a typed array in the module's memory. Must not be accessed anymore afterwards. */
function freeArray(ptr) { // function freeArray(ptr) {
checkMem(); // checkMem();
var buf = U32[ptr >>> 2]; // var buf = U32[ptr >>> 2];
memory_free(buf); // free(buf);
memory_free(ptr); // 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 // * 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. // * WebAssembly functions, i.e. as exported by the module, are supported.
*/ // */
function newFunction(fn) { // function newFunction(fn) {
if (typeof fn.original === "function") fn = fn.original; // if (typeof fn.original === "function") fn = fn.original;
var index = table.length; // var index = table.length;
table.grow(1); // table.grow(1);
table.set(index, fn); // table.set(index, fn);
return index; // return index;
} // }
baseModule.newFunction = newFunction; // baseModule.newFunction = newFunction;
/** Gets a function by its pointer. */ // /** Gets a function by its pointer. */
function getFunction(ptr) { // function getFunction(ptr) {
return wrapFunction(table.get(ptr), setargc); // return wrapFunction(table.get(ptr), setargc);
} // }
baseModule.getFunction = getFunction; // baseModule.getFunction = getFunction;
// Pull basic exports to baseModule so code in preInstantiate can use them // Pull basic exports to baseModule so code in preInstantiate can use them
baseModule.memory = baseModule.memory || memory; baseModule.memory = baseModule.memory || memory;
@ -253,7 +254,7 @@ exports.instantiateStreaming = instantiateStreaming;
/** Demangles an AssemblyScript module's exports to a friendly object structure. */ /** Demangles an AssemblyScript module's exports to a friendly object structure. */
function demangle(exports, baseModule) { function demangle(exports, baseModule) {
var module = baseModule ? Object.create(baseModule) : {}; var module = baseModule ? Object.create(baseModule) : {};
var setargc = exports[".setargc"] || function() {}; var setargc = exports["__setargc"] || function() {};
function hasOwnProperty(elem, prop) { function hasOwnProperty(elem, prop) {
return Object.prototype.hasOwnProperty.call(elem, prop); return Object.prototype.hasOwnProperty.call(elem, prop);
} }

View File

@ -1,5 +1,3 @@
import "allocator/tlsf";
export { memory }; export { memory };
export const COLOR: string = "red"; export const COLOR: string = "red";
@ -39,10 +37,6 @@ export class Car {
this.doorsOpen = false; this.doorsOpen = false;
return true; return true;
} }
dispose(): void {
memory.free(changetype<usize>(this));
}
} }
export function sum(arr: Int32Array): i32 { export function sum(arr: Int32Array): i32 {

View File

@ -21,7 +21,7 @@ assert(proto.F64 instanceof Float64Array);
// should export memory // should export memory
assert(module.memory instanceof WebAssembly.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 // should be able to get an exported string
assert.strictEqual(module.getString(module.COLOR), "red"); assert.strictEqual(module.getString(module.COLOR), "red");
@ -33,17 +33,17 @@ assert.strictEqual(module.getString(ptr), str);
assert.strictEqual(module.strlen(ptr), str.length); assert.strictEqual(module.strlen(ptr), str.length);
// should be able to allocate a typed array and sum up its values // should be able to allocate a typed array and sum up its values
var arr = [1, 2, 3, 4, 5, 0x7fffffff]; // var arr = [1, 2, 3, 4, 5, 0x7fffffff];
ptr = module.newArray(new Int32Array(arr)); // ptr = module.newArray(new Int32Array(arr));
assert.strictEqual(module.sum(ptr), arr.reduce((a, b) => a + b, 0) | 0); // 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 // 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 // should be able to free and reuse the space of an internal typed array
module.freeArray(ptr); // module.freeArray(ptr);
var ptr2 = module.newArray(new Int32Array(arr)); // var ptr2 = module.newArray(new Int32Array(arr));
assert.strictEqual(ptr, ptr2); // assert.strictEqual(ptr, ptr2);
// should be able to just call a function with variable arguments // should be able to just call a function with variable arguments
assert.strictEqual(module.varadd(), 3); assert.strictEqual(module.varadd(), 3);
@ -51,14 +51,14 @@ assert.strictEqual(module.varadd(2, 3), 5);
assert.strictEqual(module.varadd(2), 4); assert.strictEqual(module.varadd(2), 4);
// should be able to get a function from the table and just call it with variable arguments // should be able to get a function from the table and just call it with variable arguments
var fn = module.getFunction(module.varadd_ptr); // var fn = module.getFunction(module.varadd_ptr);
assert.strictEqual(fn(), 3); // assert.strictEqual(fn(), 3);
assert.strictEqual(fn(2, 3), 5); // assert.strictEqual(fn(2, 3), 5);
assert.strictEqual(fn(2), 4); // assert.strictEqual(fn(2), 4);
// should be able to create a new function and call it from WASM // should be able to create a new function and call it from WASM
ptr = module.newFunction(module.varadd); // ptr = module.newFunction(module.varadd);
assert.strictEqual(module.calladd(ptr, 2, 3), 5); // assert.strictEqual(module.calladd(ptr, 2, 3), 5);
// should be able to use a class // should be able to use a class
var car = new module.Car(5); var car = new module.Car(5);

View File

@ -6489,7 +6489,7 @@ export class Compiler extends DiagnosticEmitter {
module.createGetLocal(0, NativeType.I32) module.createGetLocal(0, NativeType.I32)
) )
); );
module.addFunctionExport(BuiltinSymbols.setargc, "$.setArgc"); module.addFunctionExport(BuiltinSymbols.setargc, "__setargc");
} }
return BuiltinSymbols.setargc; return BuiltinSymbols.setargc;
} }

View File

@ -20,7 +20,7 @@
(global $exports/vehicles.Car i32 (i32.const 4)) (global $exports/vehicles.Car i32 (i32.const 4))
(export "memory" (memory $0)) (export "memory" (memory $0))
(export "add" (func $exports/add)) (export "add" (func $exports/add))
(export "$.setArgc" (func $~lib/setargc)) (export "__setargc" (func $~lib/setargc))
(export "subOpt" (func $exports/subOpt|trampoline)) (export "subOpt" (func $exports/subOpt|trampoline))
(export "math.sub" (func $exports/subOpt)) (export "math.sub" (func $exports/subOpt))
(export "Animal.CAT" (global $exports/Animal.CAT)) (export "Animal.CAT" (global $exports/Animal.CAT))

View File

@ -23,7 +23,7 @@
(global $exports/vehicles.Car i32 (i32.const 4)) (global $exports/vehicles.Car i32 (i32.const 4))
(export "memory" (memory $0)) (export "memory" (memory $0))
(export "add" (func $exports/add)) (export "add" (func $exports/add))
(export "$.setArgc" (func $~lib/setargc)) (export "__setargc" (func $~lib/setargc))
(export "subOpt" (func $exports/subOpt|trampoline)) (export "subOpt" (func $exports/subOpt|trampoline))
(export "math.sub" (func $exports/math.sub)) (export "math.sub" (func $exports/math.sub))
(export "Animal.CAT" (global $exports/Animal.CAT)) (export "Animal.CAT" (global $exports/Animal.CAT))