Skip to content

Generalize runtime #1503

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Oct 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions lib/loader/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ export interface ASUtil {

/** 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;
/** Allocates a new array in the module's memory and returns a reference (pointer) to it. */
__allocArray(id: number, values: ArrayLike<number>): number;

/** Copies a string's value from the module's memory. */
__getString(ptr: number): string;
Expand Down Expand Up @@ -85,14 +81,18 @@ export interface ASUtil {
/** Gets a live view on a Float64Array's values in the module's memory. */
__getFloat64ArrayView(ptr: number): Float64Array;

/** Allocates an instance of the class represented by the specified id. */
__new(size: number, id: number): number;
/** Allocates a new string in the module's memory and returns a reference (pointer) to it. */
__newString(str: string): number;
/** Allocates a new array in the module's memory and returns a reference (pointer) to it. */
__newArray(id: number, values: ArrayLike<number>): number;
/** 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;
/** Forcefully resets the heap to its initial offset, effectively clearing dynamic memory. Stub runtime only. */
__reset?(): void;
/** Allocates an instance of the class represented by the specified id. */
__alloc(size: number, id: number): number;
/** 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. */
Expand Down
16 changes: 8 additions & 8 deletions lib/loader/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ function postInstantiate(extendedExports, instance) {
const exports = instance.exports;
const memory = exports.memory;
const table = exports.table;
const alloc = exports["__alloc"];
const new_ = exports["__new"];
const retain = exports["__retain"];
const rttiBase = exports["__rtti_base"] || ~0; // oob if not present

Expand Down Expand Up @@ -119,15 +119,15 @@ function postInstantiate(extendedExports, instance) {
// }

/** Allocates a new string in the module's memory and returns its retained pointer. */
function __allocString(str) {
function __newString(str) {
const length = str.length;
const ptr = alloc(length << 1, STRING_ID);
const ptr = new_(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;
}

extendedExports.__allocString = __allocString;
extendedExports.__newString = __newString;

/** Reads a string from the module's memory by its pointer. */
function __getString(ptr) {
Expand Down Expand Up @@ -159,16 +159,16 @@ function postInstantiate(extendedExports, instance) {
}

/** Allocates a new array in the module's memory and returns its retained pointer. */
function __allocArray(id, values) {
function __newArray(id, values) {
const info = getArrayInfo(id);
const align = getValueAlign(info);
const length = values.length;
const buf = alloc(length << align, info & STATICARRAY ? id : ARRAYBUFFER_ID);
const buf = new_(length << align, info & STATICARRAY ? id : ARRAYBUFFER_ID);
let result;
if (info & STATICARRAY) {
result = buf;
} else {
const arr = alloc(info & ARRAY ? ARRAY_SIZE : ARRAYBUFFERVIEW_SIZE, id);
const arr = new_(info & ARRAY ? ARRAY_SIZE : ARRAYBUFFERVIEW_SIZE, id);
const U32 = new Uint32Array(memory.buffer);
U32[arr + ARRAYBUFFERVIEW_BUFFER_OFFSET >>> 2] = retain(buf);
U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2] = buf;
Expand All @@ -185,7 +185,7 @@ function postInstantiate(extendedExports, instance) {
return result;
}

extendedExports.__allocArray = __allocArray;
extendedExports.__newArray = __newArray;

/** Gets a live view on an array's values in the module's memory. Infers the array type from RTTI. */
function __getArrayView(arr) {
Expand Down
Binary file modified lib/loader/tests/build/default.wasm
Binary file not shown.
Binary file modified lib/loader/tests/build/legacy.wasm
Binary file not shown.
34 changes: 17 additions & 17 deletions lib/loader/tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function test(file) {
// should be able to allocate and work with a new small string
{
let str = "Hello world!𤭢";
let ref = exports.__retain(exports.__allocString(str));
let ref = exports.__retain(exports.__newString(str));
assert.strictEqual(exports.__getString(ref), str);
assert.strictEqual(exports.strlen(ref), str.length);
exports.__release(ref);
Expand All @@ -46,7 +46,7 @@ function test(file) {
≔ ≕ ≖ ≗ ≘ ≙ ≚ ≛ ≜ ≝ ≞ ≟ ≠ ≡ ≢ ≣ ≤ ≥ ≦ ≧ ≨ ≩ ≪ ≫ ≬ ≭ ≮ ≯
≰ ≱ ≲ ≳ ≴ ≵ ≶ ≷ ≸ ≹ ≺ ≻ ≼ ≽ ≾ ≿
`;
let ref = exports.__retain(exports.__allocString(str));
let ref = exports.__retain(exports.__newString(str));
assert.strictEqual(exports.__getString(ref), str);
assert.strictEqual(exports.strlen(ref), str.length);
exports.__release(ref);
Expand All @@ -55,7 +55,7 @@ function test(file) {
// should be able to allocate a typed array
{
let arr = [1, 2, 3, 4, 5, 0x80000000 | 0];
let ref = exports.__retain(exports.__allocArray(exports.INT32ARRAY_ID, arr));
let ref = exports.__retain(exports.__newArray(exports.INT32ARRAY_ID, arr));
assert(exports.__instanceof(ref, exports.INT32ARRAY_ID));

// should be able to get the values of an array
Expand All @@ -75,7 +75,7 @@ function test(file) {
// should be able to allocate a typed array
{
let arr = [1, 2, 3, 4, 5, 0x80000000 | 0];
let ref = exports.__retain(exports.__allocArray(exports.STATICARRAYI32_ID, arr));
let ref = exports.__retain(exports.__newArray(exports.STATICARRAYI32_ID, arr));
assert(exports.__instanceof(ref, exports.STATICARRAYI32_ID));

// should be able to get the values of an array
Expand All @@ -95,21 +95,21 @@ function test(file) {
/*
{
let arrU8Arr = new Uint8Array([0, 1, 2]);
let refU8Arr = module.__retain(module.__allocUint8Array(arrU8Arr));
let refU8Arr = module.__retain(module.__newUint8Array(arrU8Arr));
assert(module.__instanceof(refU8Arr, module.UINT8ARRAY_ID));
assert.deepEqual(module.__getUint8Array(refU8Arr), arrU8Arr);
module.__release(refU8Arr);
try { module.__release(refU8Arr); assert(false); } catch (e) {};
let arrU16Arr = new Uint16Array([0, 0x7FFF, 0xFFFF]);
let refU16Arr = module.__retain(module.__allocUint16Array(arrU16Arr));
let refU16Arr = module.__retain(module.__newUint16Array(arrU16Arr));
assert(module.__instanceof(refU16Arr, module.UINT16ARRAY_ID));
assert.deepEqual(module.__getUint16Array(refU16Arr), arrU16Arr);
module.__release(refU16Arr);
try { module.__release(refU16Arr); assert(false); } catch (e) {};
let arrI16Arr = new Int16Array([0, -1, -2]);
let refI16Arr = module.__retain(module.__allocInt16Array(arrI16Arr));
let refI16Arr = module.__retain(module.__newInt16Array(arrI16Arr));
assert(module.__instanceof(refI16Arr, module.INT16ARRAY_ID));
assert.deepEqual(module.__getInt16Array(refI16Arr), arrI16Arr);
module.__release(refI16Arr);
Expand All @@ -121,7 +121,7 @@ function test(file) {
{
let values = [0, 255, 127];
let arr = new Uint8Array(values);
let ref = exports.__retain(exports.__allocArray(exports.UINT8ARRAY_ID, arr));
let ref = exports.__retain(exports.__newArray(exports.UINT8ARRAY_ID, arr));
assert(exports.__instanceof(ref, exports.UINT8ARRAY_ID));
assert.deepEqual(exports.__getUint8Array(ref), arr);
assert.deepEqual(exports.__getUint8ArrayView(ref), arr);
Expand All @@ -133,7 +133,7 @@ function test(file) {
// should be able to distinguish between signed and unsigned for static array layout
{
let arr = [0, 255, 127];
let ref = exports.__retain(exports.__allocArray(exports.STATICARRAYU8_ID, arr));
let ref = exports.__retain(exports.__newArray(exports.STATICARRAYU8_ID, arr));
assert(exports.__instanceof(ref, exports.STATICARRAYU8_ID));
assert.deepEqual(exports.__getArray(ref), arr);
exports.__release(ref);
Expand All @@ -144,7 +144,7 @@ function test(file) {
{
let values = [0, 0xFFFF, -0x00FF];
let arr = new Int16Array(values);
let ref = exports.__retain(exports.__allocArray(exports.INT16ARRAY_ID, arr));
let ref = exports.__retain(exports.__newArray(exports.INT16ARRAY_ID, arr));
assert(exports.__instanceof(ref, exports.INT16ARRAY_ID));
assert.deepEqual(exports.__getInt16Array(ref), arr);
assert.deepEqual(exports.__getInt16ArrayView(ref), arr);
Expand All @@ -156,7 +156,7 @@ function test(file) {
// should be able to distinguish between signed and unsigned for static array layout
{
let arr = [0, 0xFFFF, -0x00FF];
let ref = exports.__retain(exports.__allocArray(exports.STATICARRAYI16_ID, arr));
let ref = exports.__retain(exports.__newArray(exports.STATICARRAYI16_ID, arr));
assert(exports.__instanceof(ref, exports.STATICARRAYI16_ID));
assert.deepEqual(exports.__getArray(ref), [0, -1, -255]);
exports.__release(ref);
Expand All @@ -167,7 +167,7 @@ function test(file) {
{
let values = [1, -1 >>> 0, 0x80000000];
let arr = new Uint32Array(values);
let ref = exports.__retain(exports.__allocArray(exports.UINT32ARRAY_ID, arr));
let ref = exports.__retain(exports.__newArray(exports.UINT32ARRAY_ID, arr));
assert(exports.__instanceof(ref, exports.UINT32ARRAY_ID));
assert.deepEqual(exports.__getUint32Array(ref), arr);
assert.deepEqual(exports.__getUint32ArrayView(ref), arr);
Expand All @@ -179,7 +179,7 @@ function test(file) {
// should be able to distinguish between signed and unsigned with static array layout
{
let arr = [1, -1 >>> 0, 0x80000000];
let ref = exports.__retain(exports.__allocArray(exports.STATICARRAYU32_ID, arr));
let ref = exports.__retain(exports.__newArray(exports.STATICARRAYU32_ID, arr));
assert(exports.__instanceof(ref, exports.STATICARRAYU32_ID));
assert.deepEqual(exports.__getArray(ref), arr);
exports.__release(ref);
Expand All @@ -190,7 +190,7 @@ function test(file) {
{
let values = [0.0, 1.5, 2.5];
let arr = new Float32Array(values);
let ref = exports.__retain(exports.__allocArray(exports.FLOAT32ARRAY_ID, arr));
let ref = exports.__retain(exports.__newArray(exports.FLOAT32ARRAY_ID, arr));
assert(exports.__instanceof(ref, exports.FLOAT32ARRAY_ID));
assert.deepEqual(exports.__getFloat32Array(ref), arr);
assert.deepEqual(exports.__getFloat32ArrayView(ref), arr);
Expand All @@ -202,7 +202,7 @@ function test(file) {
// should be able to distinguish between integer and float static arrays
{
let arr = [0.0, 1.5, 2.5];
let ref = exports.__retain(exports.__allocArray(exports.STATICARRAYF32_ID, arr));
let ref = exports.__retain(exports.__newArray(exports.STATICARRAYF32_ID, arr));
assert(exports.__instanceof(ref, exports.STATICARRAYF32_ID));
assert.deepEqual(exports.__getArray(ref), arr);
exports.__release(ref);
Expand All @@ -212,7 +212,7 @@ function test(file) {
// should be able to work with normal arrays
{
let arr = [1, 2, 3, 4, 5];
let ref = exports.__retain(exports.__allocArray(exports.ARRAYI32_ID, arr));
let ref = exports.__retain(exports.__newArray(exports.ARRAYI32_ID, arr));
assert(exports.__instanceof(ref, exports.ARRAYI32_ID));
exports.changeLength(ref, 3);
assert.deepEqual(exports.__getArray(ref), [1, 2, 3]);
Expand Down Expand Up @@ -252,7 +252,7 @@ function test(file) {

// should be able to mutate an array in place using getArrayView
{
let ptr = exports.__retain(exports.__allocArray(exports.FLOAT32ARRAY_ID, [1, 2, 3]));
let ptr = exports.__retain(exports.__newArray(exports.FLOAT32ARRAY_ID, [1, 2, 3]));
let view = exports.__getArrayView(ptr);
assert.deepEqual(view, new Float32Array([1, 2, 3]));
exports.modifyFloat32Array(ptr, 0, 4);
Expand Down
16 changes: 8 additions & 8 deletions lib/loader/umd/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ var loader = (function(exports) {
const exports = instance.exports;
const memory = exports.memory;
const table = exports.table;
const alloc = exports["__alloc"];
const new_ = exports["__new"];
const retain = exports["__retain"];
const rttiBase = exports["__rtti_base"] || ~0; // oob if not present

Expand Down Expand Up @@ -138,17 +138,17 @@ var loader = (function(exports) {
/** Allocates a new string in the module's memory and returns its retained pointer. */


function __allocString(str) {
function __newString(str) {
const length = str.length;
const ptr = alloc(length << 1, STRING_ID);
const ptr = new_(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;
}

extendedExports.__allocString = __allocString;
extendedExports.__newString = __newString;
/** Reads a string from the module's memory by its pointer. */

function __getString(ptr) {
Expand Down Expand Up @@ -193,17 +193,17 @@ var loader = (function(exports) {
/** Allocates a new array in the module's memory and returns its retained pointer. */


function __allocArray(id, values) {
function __newArray(id, values) {
const info = getArrayInfo(id);
const align = getValueAlign(info);
const length = values.length;
const buf = alloc(length << align, info & STATICARRAY ? id : ARRAYBUFFER_ID);
const buf = new_(length << align, info & STATICARRAY ? id : ARRAYBUFFER_ID);
let result;

if (info & STATICARRAY) {
result = buf;
} else {
const arr = alloc(info & ARRAY ? ARRAY_SIZE : ARRAYBUFFERVIEW_SIZE, id);
const arr = new_(info & ARRAY ? ARRAY_SIZE : ARRAYBUFFERVIEW_SIZE, id);
const U32 = new Uint32Array(memory.buffer);
U32[arr + ARRAYBUFFERVIEW_BUFFER_OFFSET >>> 2] = retain(buf);
U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2] = buf;
Expand All @@ -223,7 +223,7 @@ var loader = (function(exports) {
return result;
}

extendedExports.__allocArray = __allocArray;
extendedExports.__newArray = __newArray;
/** Gets a live view on an array's values in the module's memory. Infers the array type from RTTI. */

function __getArrayView(arr) {
Expand Down
10 changes: 6 additions & 4 deletions lib/rtrace/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const PTR_SIZE = 1 << PTR_SIZE_BITS;
const PTR_MASK = PTR_SIZE - 1;
const PTR_VIEW = Uint32Array;

const BLOCK_OVERHEAD = 16;
const BLOCK_OVERHEAD = PTR_SIZE;

function assert(x) {
if (!x) throw Error("assertion failed");
Expand Down Expand Up @@ -142,9 +142,10 @@ class Rtrace {

/** Obtains information about a block. */
getBlockInfo(ptr) {
var header = new Uint32Array(this.memory.buffer, ptr, 4);
var header = new Uint32Array(this.memory.buffer, ptr, 5);
var mmInfo = header[0];
var gcInfo = header[1];
var gcInfo2 = header[2];
const mmTags = [ // 0│L│F
[],
["FREE"],
Expand All @@ -171,8 +172,9 @@ class Rtrace {
color: gcColor[gcInfo << 1 >>> 29],
rc: gcInfo << 4 >>> 4
},
rtId: header[2],
rtSize: header[3]
gcInfo2,
rtId: header[3],
rtSize: header[4]
}
};
}
Expand Down
8 changes: 4 additions & 4 deletions src/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ export namespace BuiltinNames {
export const v64x2_load_splat = "~lib/builtins/v64x2.load_splat";

// internals
export const heap_base = "~lib/heap/__heap_base";
export const heap_base = "~lib/memory/__heap_base";
export const rtti_base = "~lib/rt/__rtti_base";
export const visit_globals = "~lib/rt/__visit_globals";
export const visit_members = "~lib/rt/__visit_members";
Expand Down Expand Up @@ -2875,7 +2875,7 @@ function builtin_memory_data(ctx: BuiltinContext): ExpressionRef {
}
let buf = new Uint8Array(numElements * elementType.byteSize);
assert(compiler.writeStaticBuffer(buf, 0, elementType, exprs) == buf.byteLength);
offset = compiler.addMemorySegment(buf, align).offset;
offset = compiler.addAlignedMemorySegment(buf, align).offset;
} else { // data(size[, align])
let arg0 = compiler.compileExpression(operands[0], Type.i32, Constraints.CONV_IMPLICIT);
let precomp = module.runExpression(arg0, ExpressionRunnerFlags.PreserveSideeffects);
Expand Down Expand Up @@ -2904,7 +2904,7 @@ function builtin_memory_data(ctx: BuiltinContext): ExpressionRef {
return module.unreachable();
}
}
offset = compiler.addMemorySegment(new Uint8Array(size), align).offset;
offset = compiler.addAlignedMemorySegment(new Uint8Array(size), align).offset;
}
// FIXME: what if recompiles happen? recompiles are bad.
compiler.currentType = usizeType;
Expand Down Expand Up @@ -8885,7 +8885,7 @@ export function compileRTTI(compiler: Compiler): void {
}
assert(off == size);
var usizeType = program.options.usizeType;
var segment = compiler.addMemorySegment(data);
var segment = compiler.addAlignedMemorySegment(data);
if (usizeType.size == 8) {
let offset = segment.offset;
module.addGlobal(BuiltinNames.rtti_base, NativeType.I64, false, module.i64(i64_low(offset), i64_high(offset)));
Expand Down
8 changes: 6 additions & 2 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,18 @@ export namespace CommonNames {
export const alloc = "__alloc";
export const realloc = "__realloc";
export const free = "__free";
export const new_ = "__new";
export const renew = "__renew";
export const retain = "__retain";
export const release = "__release";
export const collect = "__collect";
export const typeinfo = "__typeinfo";
export const instanceof_ = "__instanceof";
export const visit = "__visit";
export const allocBuffer = "__allocBuffer";
export const allocArray = "__allocArray";
export const newBuffer = "__newBuffer";
export const newArray = "__newArray";
export const BLOCK = "~lib/rt/common/BLOCK";
export const OBJECT = "~lib/rt/common/OBJECT";
}

// shared
Expand Down
Loading