Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Fresh Starting point
  • Loading branch information
jtenner committed Mar 27, 2020
commit da34d8d3ef5cda49c86c92ba24ca6bb6a49e0d54
101 changes: 57 additions & 44 deletions lib/loader/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,21 @@ const ARRAYBUFFERVIEW_ID = 2;
// Runtime type information
const ARRAYBUFFERVIEW = 1 << 0;
const ARRAY = 1 << 1;
const SET = 1 << 2;
const MAP = 1 << 3;
const VAL_ALIGN_OFFSET = 5;
const STATICARRAY = 1 << 2;
const SET = 1 << 3;
const MAP = 1 << 4;
const VAL_ALIGN_OFFSET = 6;
const VAL_ALIGN = 1 << VAL_ALIGN_OFFSET;
const VAL_SIGNED = 1 << 10;
const VAL_FLOAT = 1 << 11;
const VAL_NULLABLE = 1 << 12;
const VAL_MANAGED = 1 << 13;
const KEY_ALIGN_OFFSET = 14;
const VAL_SIGNED = 1 << 11;
const VAL_FLOAT = 1 << 12;
const VAL_NULLABLE = 1 << 13;
const VAL_MANAGED = 1 << 14;
const KEY_ALIGN_OFFSET = 15;
const KEY_ALIGN = 1 << KEY_ALIGN_OFFSET;
const KEY_SIGNED = 1 << 19;
const KEY_FLOAT = 1 << 20;
const KEY_NULLABLE = 1 << 21;
const KEY_MANAGED = 1 << 22;
const KEY_SIGNED = 1 << 20;
const KEY_FLOAT = 1 << 21;
const KEY_NULLABLE = 1 << 22;
const KEY_MANAGED = 1 << 23;

// Array(BufferView) layout
const ARRAYBUFFERVIEW_BUFFER_OFFSET = 0;
Expand Down Expand Up @@ -162,23 +163,29 @@ function postInstantiate(extendedExports, instance) {
/** Allocates a new array in the module's memory and returns its retained pointer. */
function __allocArray(id, values) {
const info = getInfo(id);
if (!(info & (ARRAYBUFFERVIEW | ARRAY))) throw Error("not an array: " + id + ", flags= " + info);
if (!(info & (ARRAYBUFFERVIEW | ARRAY | STATICARRAY))) throw Error("not an array: " + id + ", flags= " + info);
const align = getValueAlign(info);
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);
U32[arr + ARRAYBUFFERVIEW_BUFFER_OFFSET >>> 2] = retain(buf);
U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2] = buf;
U32[arr + ARRAYBUFFERVIEW_DATALENGTH_OFFSET >>> 2] = length << align;
if (info & ARRAY) U32[arr + ARRAY_LENGTH_OFFSET >>> 2] = length;
let result;
if (info & STATICARRAY) {
result = buf;
} else {
const arr = alloc(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;
U32[arr + ARRAYBUFFERVIEW_DATALENGTH_OFFSET >>> 2] = length << align;
if (info & ARRAY) U32[arr + ARRAY_LENGTH_OFFSET >>> 2] = length;
result = arr;
}
const view = getView(align, info & VAL_SIGNED, info & VAL_FLOAT);
if (info & VAL_MANAGED) {
for (let i = 0; i < length; ++i) view[(buf >>> align) + i] = retain(values[i]);
} else {
view.set(values, buf >>> align);
}
return arr;
return result;
}

extendedExports.__allocArray = __allocArray;
Expand All @@ -188,9 +195,11 @@ function postInstantiate(extendedExports, instance) {
const U32 = new Uint32Array(memory.buffer);
const id = U32[arr + ID_OFFSET >>> 2];
const info = getInfo(id);
if (!(info & (ARRAYBUFFERVIEW | ARRAY))) throw Error("not an array: " + id + ", flags=" + info);
if (!(info & (ARRAYBUFFERVIEW | ARRAY | STATICARRAY))) throw Error("not an array: " + id + ", flags=" + info);
const align = getValueAlign(info);
let buf = U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2];
let buf = info & STATICARRAY
? arr
: U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2];
const length = info & ARRAY
? U32[arr + ARRAY_LENGTH_OFFSET >>> 2]
: U32[buf + SIZE_OFFSET >>> 2] >>> align;
Expand Down Expand Up @@ -233,30 +242,34 @@ function postInstantiate(extendedExports, instance) {
return new Type(buffer, bufPtr, U32[bufPtr + SIZE_OFFSET >>> 2] >>> alignLog2);
}

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);
const ctors = [
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array
];

/** Attach a set of get TypedArray and View functions to the exports. */
function attachTypedArrayFunctions(ctor, name, align) {
extendedExports["__get" + name] = getTypedArray.bind(null, ctor, align);
extendedExports["__get" + name + "View"] = getTypedArrayView.bind(null, ctor, align);
}

ctors.forEach(ctor => {
attachTypedArrayFunctions(ctor, ctor.name, 31 - Math.clz32(ctor.BYTES_PER_ELEMENT));
});

if (BIGINT) {
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);
const bigctors = [BigUint64Array, BigInt64Array];
ctors.forEach(ctor => {
attachTypedArrayFunctions(ctor, ctor.name.slice(3), 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) {
Expand Down
11 changes: 11 additions & 0 deletions lib/loader/tests/assembly/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/// <reference path="../../../../std/assembly/index.d.ts" />
export { memory };

export const COLOR: string = "red";
Expand Down Expand Up @@ -45,6 +46,12 @@ export function sum(arr: Int32Array): i32 {
return v;
}

export function sumStatic(arr: StaticArray<i32>): i32 {
var v = 0;
for (let i = 0, k = arr.length; i < k; ++i) v += arr[i];
return v;
}

export function changeLength(arr: Array<i32>, length: i32): void {
arr.length = length;
}
Expand All @@ -70,6 +77,10 @@ export const INT32ARRAY_ID = idof<Int32Array>();
export const UINT32ARRAY_ID = idof<Uint32Array>();
export const FLOAT32ARRAY_ID = idof<Float32Array>();
export const ARRAYI32_ID = idof<Array<i32>>();
export const STATICARRAYI32_ID = idof<StaticArray<i32>>();
export const STATICARRAYU8_ID = idof<StaticArray<u8>>();
export const STATICARRAYI16_ID = idof<StaticArray<i16>>();
export const STATICARRAYF32_ID = idof<StaticArray<f32>>();

export function newFloat32Array(size: i32): Float32Array {
return new Float32Array(size);
Expand Down
64 changes: 64 additions & 0 deletions lib/loader/tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,26 @@ function test(file) {
try { exports.__release(ref); assert(false); } catch (e) {};
}

// should be able to allocate a typed array
{
var arr = [1, 2, 3, 4, 5, 0x80000000 | 0];
let ref = exports.__retain(exports.__allocArray(exports.STATICARRAYI32_ID, arr));
assert(exports.__instanceof(ref, exports.STATICARRAYI32_ID));

// should be able to get the values of an array
assert.deepEqual(exports.__getArray(ref), arr);

// should be able to get a view on an array
assert.deepEqual(exports.__getArrayView(ref), new Int32Array(arr));

// should be able to sum up its values
assert.strictEqual(exports.sumStatic(ref), arr.reduce((a, b) => (a + b) | 0, 0) | 0);

// should be able to release no longer needed references
exports.__release(ref);
try { exports.__release(ref); assert(false); } catch (e) {};
}

/*
{
let arrU8Arr = new Uint8Array([0, 1, 2]);
Expand Down Expand Up @@ -84,6 +104,18 @@ function test(file) {
let ref = exports.__retain(exports.__allocArray(exports.UINT8ARRAY_ID, arr));
assert(exports.__instanceof(ref, exports.UINT8ARRAY_ID));
assert.deepEqual(exports.__getUint8Array(ref), arr);
assert.deepEqual(exports.__getUint8ArrayView(ref), arr);
assert.deepEqual(exports.__getArray(ref), arr);
exports.__release(ref);
try { exports.__release(ref); assert(false); } catch (e) {};
}

// should be able to distinguish between signed and unsigned for static array layout
{
let arr = new Uint8Array([0, 255, 127]);
let ref = exports.__retain(exports.__allocArray(exports.STATICARRAYU8_ID, arr));
assert(exports.__instanceof(ref, exports.STATICARRAYU8_ID));
assert.deepEqual(exports.__getArray(ref), arr);
exports.__release(ref);
try { exports.__release(ref); assert(false); } catch (e) {};
}
Expand All @@ -94,6 +126,18 @@ function test(file) {
let ref = exports.__retain(exports.__allocArray(exports.INT16ARRAY_ID, arr));
assert(exports.__instanceof(ref, exports.INT16ARRAY_ID));
assert.deepEqual(exports.__getInt16Array(ref), arr);
assert.deepEqual(exports.__getInt16ArrayView(ref), arr);
assert.deepEqual(exports.__getArray(ref), arr);
exports.__release(ref);
try { exports.__release(ref); assert(false); } catch (e) {};
}

// should be able to distinguish between signed and unsigned for static array layout
{
let arr = new Int16Array([0, 0xFFFF, -0x00FF]);
let ref = exports.__retain(exports.__allocArray(exports.STATICARRAYI16_ID, arr));
assert(exports.__instanceof(ref, exports.STATICARRAYI16_ID));
assert.deepEqual(exports.__getArray(ref), arr);
exports.__release(ref);
try { exports.__release(ref); assert(false); } catch (e) {};
}
Expand All @@ -110,6 +154,16 @@ function test(file) {
try { exports.__release(ref); assert(false); } catch (e) {};
}

// 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));
assert(exports.__instanceof(ref, exports.STATICARRAYU32_ID));
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];
Expand All @@ -122,6 +176,16 @@ function test(file) {
try { exports.__release(ref); assert(false); } catch (e) {};
}

// 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));
assert(exports.__instanceof(ref, exports.STATICARRAYF32_ID));
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];
Expand Down
5 changes: 5 additions & 0 deletions src/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7899,6 +7899,7 @@ export function compileRTTI(compiler: Compiler): void {
var arrayPrototype = program.arrayPrototype;
var setPrototype = program.setPrototype;
var mapPrototype = program.mapPrototype;
var staticArrayPrototype = program.staticArrayPrototype;
var lastId = 0;
// TODO: for (let [instanceId, instance] of managedClasses) {
for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) {
Expand Down Expand Up @@ -7926,6 +7927,10 @@ export function compileRTTI(compiler: Compiler): void {
flags |= TypeinfoFlags.MAP;
flags |= TypeinfoFlags.KEY_ALIGN_0 * typeToRuntimeFlags(typeArguments[0]);
flags |= TypeinfoFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(typeArguments[1]);
} else if (instance.extends(staticArrayPrototype)) {
let valueType = instance.getArrayValueType();
flags |= TypeinfoFlags.STATICARRAY;
flags |= TypeinfoFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(valueType);
}
writeI32(flags, data, off); off += 4;
instance.rttiFlags = flags;
Expand Down
4 changes: 4 additions & 0 deletions src/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3758,6 +3758,10 @@ export class Class extends TypedElement {
if (this.extends(arrayPrototype)) {
return this.getTypeArgumentsTo(arrayPrototype)![0];
}
var staticArrayPrototype = program.staticArrayPrototype;
if (this.extends(staticArrayPrototype)) {
return this.getTypeArgumentsTo(staticArrayPrototype)![0];
}
var abvInstance = program.arrayBufferViewInstance;
while (current.base !== abvInstance) {
current = assert(current.base);
Expand Down
44 changes: 23 additions & 21 deletions std/assembly/shared/typeinfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,46 +29,48 @@ export const enum TypeinfoFlags {
ARRAYBUFFERVIEW = 1 << 0,
/** Type is an `Array`. */
ARRAY = 1 << 1,
/** Type is a `StaticArray`. */
STATICARRAY = 1 << 2,
/** Type is a `Set`. */
SET = 1 << 2,
SET = 1 << 3,
/** Type is a `Map`. */
MAP = 1 << 3,
MAP = 1 << 4,
/** Type is inherently acyclic. */
ACYCLIC = 1 << 4,
ACYCLIC = 1 << 5,
/** Value alignment of 1 byte. */
VALUE_ALIGN_0 = 1 << 5,
VALUE_ALIGN_0 = 1 << 6,
/** Value alignment of 2 bytes. */
VALUE_ALIGN_1 = 1 << 6,
VALUE_ALIGN_1 = 1 << 7,
/** Value alignment of 4 bytes. */
VALUE_ALIGN_2 = 1 << 7,
VALUE_ALIGN_2 = 1 << 8,
/** Value alignment of 8 bytes. */
VALUE_ALIGN_3 = 1 << 8,
VALUE_ALIGN_3 = 1 << 9,
/** Value alignment of 16 bytes. */
VALUE_ALIGN_4 = 1 << 9,
VALUE_ALIGN_4 = 1 << 10,
/** Value is a signed type. */
VALUE_SIGNED = 1 << 10,
VALUE_SIGNED = 1 << 11,
/** Value is a float type. */
VALUE_FLOAT = 1 << 11,
VALUE_FLOAT = 1 << 12,
/** Value type is nullable. */
VALUE_NULLABLE = 1 << 12,
VALUE_NULLABLE = 1 << 13,
/** Value type is managed. */
VALUE_MANAGED = 1 << 13,
VALUE_MANAGED = 1 << 14,
/** Key alignment of 1 byte. */
KEY_ALIGN_0 = 1 << 14,
KEY_ALIGN_0 = 1 << 15,
/** Key alignment of 2 bytes. */
KEY_ALIGN_1 = 1 << 15,
KEY_ALIGN_1 = 1 << 16,
/** Key alignment of 4 bytes. */
KEY_ALIGN_2 = 1 << 16,
KEY_ALIGN_2 = 1 << 17,
/** Key alignment of 8 bytes. */
KEY_ALIGN_3 = 1 << 17,
KEY_ALIGN_3 = 1 << 18,
/** Key alignment of 16 bytes. */
KEY_ALIGN_4 = 1 << 18,
KEY_ALIGN_4 = 1 << 19,
/** Key is a signed type. */
KEY_SIGNED = 1 << 19,
KEY_SIGNED = 1 << 20,
/** Key is a float type. */
KEY_FLOAT = 1 << 20,
KEY_FLOAT = 1 << 21,
/** Key type is nullable. */
KEY_NULLABLE = 1 << 21,
KEY_NULLABLE = 1 << 22,
/** Key type is managed. */
KEY_MANAGED = 1 << 22
KEY_MANAGED = 1 << 23
}
6 changes: 3 additions & 3 deletions tests/compiler/extends-baseaggregate.optimized.wat
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
(data (i32.const 1328) "\1a\00\00\00\01\00\00\00\01\00\00\00\1a\00\00\00~\00l\00i\00b\00/\00a\00r\00r\00a\00y\00.\00t\00s")
(data (i32.const 1376) "$\00\00\00\01\00\00\00\01\00\00\00$\00\00\00I\00n\00d\00e\00x\00 \00o\00u\00t\00 \00o\00f\00 \00r\00a\00n\00g\00e")
(data (i32.const 1440) "\14\00\00\00\01\00\00\00\01\00\00\00\14\00\00\00~\00l\00i\00b\00/\00r\00t\00.\00t\00s")
(data (i32.const 1488) "\t\00\00\00\10\00\00\00\00\00\00\00\10\00\00\00\00\00\00\00\10\00\00\00\00\00\00\00\10\00\00\00\00\00\00\00\10")
(data (i32.const 1544) "\04\00\00\00\92 \00\00\00\00\00\00\92 ")
(data (i32.const 1488) "\t\00\00\00 \00\00\00\00\00\00\00 \00\00\00\00\00\00\00 \00\00\00\00\00\00\00 \00\00\00\00\00\00\00 ")
(data (i32.const 1544) "\04\00\00\00\"A\00\00\00\00\00\00\"A")
(global $~lib/rt/tlsf/ROOT (mut i32) (i32.const 0))
(global $~lib/rt/tlsf/collectLock (mut i32) (i32.const 0))
(global $~lib/rt/pure/ROOTS (mut i32) (i32.const 0))
Expand Down Expand Up @@ -1997,7 +1997,7 @@
i32.const 1492
i32.add
i32.load
i32.const 16
i32.const 32
i32.and
if
local.get $0
Expand Down
Loading