mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 15:12:12 +00:00
more loader updates
This commit is contained in:
parent
7cd04b65ef
commit
a6896d7bc2
@ -61,32 +61,19 @@ Instances are automatically populated with useful utility:
|
||||
A 64-bit float view on the memory.
|
||||
|
||||
* **newString**(str: `string`): `number`<br />
|
||||
Allocates a new string in the module's memory and returns its pointer.<sup>2</sup>
|
||||
Allocates a new string in the module's memory and returns its retained pointer. When done with the string, make sure to `Module#__release` it.
|
||||
|
||||
* **getString**(ptr: `number`): `string`<br />
|
||||
Gets a string from the module's memory by its pointer.
|
||||
Reads a string from the module's memory by its pointer.
|
||||
|
||||
* **newArray**(view: `TypedArray`, length?: `number`, unsafe?: `boolean`): `number`<br />
|
||||
Copies a typed array into the module's memory and returns its pointer.<sup>2</sup>
|
||||
* **newArray**(id: `number`, values: `number[]`): `number`<br />
|
||||
Allocates a new array in the module's memory and returns its retained pointer.
|
||||
The `id` is the unique runtime id of the respective array class. If you are using `Int32Array` for example, the best way to know the relevant value is an `export const INT32ARRAY_ID = idof<Int32Array>()`. When done with the array, make sure to `Module#__release` it.
|
||||
|
||||
* **newArray**(ctor: `TypedArrayConstructor`, length: `number`, unsafe?: `boolean`): `number`<br />
|
||||
Creates a typed array in the module's memory and returns its pointer.<sup>2</sup>
|
||||
* **getArray**(ptr: `number`): `number[]`<br />
|
||||
Gets the values of an array in the module's memory by its pointer.
|
||||
|
||||
* **getArray**(ctor: `TypedArrayConstructor`, ptr: `number`): `TypedArray`<br />
|
||||
Gets a view on a typed array in the module's memory by its pointer.
|
||||
|
||||
* **freeArray**(ptr: `number`): `void`<br />
|
||||
Frees a typed array in the module's memory. Must not be accessed anymore afterwards.
|
||||
|
||||
* **getFunction**(ptr: `number`): `function`<br />
|
||||
Gets a function by its pointer.
|
||||
|
||||
* **newFunction**(fn: `function`): `number`<br />
|
||||
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.
|
||||
|
||||
<sup>1</sup> This feature has not yet landed in any VM as of this writing.<br />
|
||||
<sup>2</sup> Requires that memory utilities have been exported through `export { memory }` within the entry file.
|
||||
<sup>1</sup> This feature has not yet landed in any VM as of this writing.
|
||||
|
||||
Examples
|
||||
--------
|
||||
@ -141,7 +128,11 @@ Strings and arrays cannot yet flow in and out of WebAssembly naturally, hence it
|
||||
var str = "Hello world!";
|
||||
var ptr = module.newString(str);
|
||||
|
||||
// ... do something with ptr, i.e. call a WebAssembly export ...
|
||||
// do something with ptr, i.e. call a WebAssembly export
|
||||
...
|
||||
|
||||
// when done, allow the runtime to collect it
|
||||
module.__release(ptr);
|
||||
```
|
||||
|
||||
Similarly, when a string or array is returned from a WebAssembly function, a reference (pointer) is received on the JS side and the `getString` and `getArray` helpers can be used to obtain their values:
|
||||
|
@ -1,18 +1,32 @@
|
||||
"use strict";
|
||||
|
||||
/** Relative header `id` offset. */
|
||||
// Runtime header offsets
|
||||
const ID_OFFSET = -8;
|
||||
/** Relative header `size` offset. */
|
||||
const SIZE_OFFSET = -4;
|
||||
|
||||
/** Unique runtime id of an `ArrayBuffer`. */
|
||||
// Runtime ids
|
||||
const ARRAYBUFFER_ID = 0;
|
||||
/** Unique runtime id of a `String`. */
|
||||
const STRING_ID = 1;
|
||||
const ARRAYBUFFERVIEW_ID = 2;
|
||||
|
||||
/** Whether BigInt arrays are supported. */
|
||||
const SUPPORTS_BIGINT = typeof BigUint64Array !== "undefined";
|
||||
/** Unique symbol for memoized 'this'. */
|
||||
// Runtime type information
|
||||
const ARRAY = 1 << 0;
|
||||
const SET = 1 << 1;
|
||||
const MAP = 1 << 2;
|
||||
const VAL_ALIGN = 1 << 4;
|
||||
const VAL_NULLABLE = 1 << 9;
|
||||
const VAL_MANAGED = 1 << 10;
|
||||
const KEY_ALIGN = 1 << 11;
|
||||
const KEY_NULLABLE = 1 << 16;
|
||||
const KEY_MANAGED = 1 << 17;
|
||||
|
||||
// ArrayBufferView layout
|
||||
const ABV_BUFFER_OFFSET = 0;
|
||||
const ABV_DATASTART_OFFSET = 4;
|
||||
const ABV_DATALENGTH_OFFSET = 8;
|
||||
const ABV_SIZE = 12;
|
||||
|
||||
const BIGINT = typeof BigUint64Array !== "undefined";
|
||||
const THIS = Symbol();
|
||||
|
||||
/** Gets a string from an U32 and an U16 view on a memory. */
|
||||
@ -61,11 +75,10 @@ function preInstantiate(imports) {
|
||||
function postInstantiate(baseModule, instance) {
|
||||
var rawExports = instance.exports;
|
||||
var memory = rawExports.memory;
|
||||
var alloc = rawExports["__alloc"];
|
||||
var free = rawExports["__free"];
|
||||
var setargc = rawExports["__setargc"] || function() {};
|
||||
var memory_fill = rawExports["memory.fill"];
|
||||
var table = rawExports.table;
|
||||
var alloc = rawExports["__alloc"];
|
||||
var retain = rawExports["__retain"];
|
||||
var rtti = rawExports["__rtti"] | 0;
|
||||
|
||||
// Provide views for all sorts of basic values
|
||||
var buffer, I8, U8, I16, U16, I32, U32, F32, F64, I64, U64;
|
||||
@ -81,7 +94,7 @@ function postInstantiate(baseModule, instance) {
|
||||
U16 = new Uint16Array(buffer);
|
||||
I32 = new Int32Array(buffer);
|
||||
U32 = new Uint32Array(buffer);
|
||||
if (SUPPORTS_BIGINT) {
|
||||
if (BIGINT) {
|
||||
I64 = new BigInt64Array(buffer);
|
||||
U64 = new BigUint64Array(buffer);
|
||||
}
|
||||
@ -91,107 +104,95 @@ function postInstantiate(baseModule, instance) {
|
||||
}
|
||||
checkMem();
|
||||
|
||||
/** Allocates a new string in the module's memory and returns its pointer. */
|
||||
/** Gets the runtime type info for the given id. */
|
||||
function getInfo(id) {
|
||||
const count = U32[rtti >>> 2];
|
||||
if ((id >>>= 0) >= count) throw Error("invalid id: " + id);
|
||||
return U32[(rtti + 4 >>> 2) + id * 2];
|
||||
}
|
||||
|
||||
/** Gets the runtime base id for the given id. */
|
||||
function getBase(id) {
|
||||
const count = U32[rtti >>> 2];
|
||||
if ((id >>>= 0) >= count) throw Error("invalid id: " + id);
|
||||
return U32[(rtti + 4 >>> 2) + id * 2 + 1];
|
||||
}
|
||||
|
||||
/** Gets the runtime alignment of a collection's values or keys. */
|
||||
function getAlign(which, info) {
|
||||
return 31 - Math.clz32((info / which) & 31);
|
||||
}
|
||||
|
||||
/** Allocates a new string in the module's memory and returns its retained pointer. */
|
||||
function newString(str) {
|
||||
var length = str.length;
|
||||
var ptr = alloc(length << 1, STRING_ID);
|
||||
const length = str.length;
|
||||
const ptr = alloc(length << 1, STRING_ID);
|
||||
checkMem();
|
||||
for (let i = 0, j = ptr >>> 1; i < length; ++i) U16[j + i] = str.charCodeAt(i);
|
||||
return ptr;
|
||||
return retain(ptr);
|
||||
}
|
||||
|
||||
baseModule.newString = newString;
|
||||
|
||||
/** Gets a string from the module's memory by its pointer. */
|
||||
/** Reads a string from the module's memory by its pointer. */
|
||||
function getString(ptr) {
|
||||
checkMem();
|
||||
const id = U32[ptr + ID_OFFSET >>> 2];
|
||||
if (id !== STRING_ID) throw Error("not a string: " + ptr);
|
||||
return getStringImpl(U32, U16, ptr);
|
||||
}
|
||||
|
||||
baseModule.getString = getString;
|
||||
|
||||
// function computeBufferSize(byteLength) {
|
||||
// const HEADER_SIZE = 8;
|
||||
// return 1 << (32 - Math.clz32(byteLength + HEADER_SIZE - 1));
|
||||
// }
|
||||
/** Allocates a new array in the module's memory and returns its retained pointer. */
|
||||
function newArray(id, values) {
|
||||
const info = getInfo(id);
|
||||
if (!(info & ARRAY)) throw Error("not an array: " + id + " @ " + info);
|
||||
const align = getAlign(VAL_ALIGN, info);
|
||||
const length = values.length;
|
||||
const buf = alloc(length << align, ARRAYBUFFER_ID);
|
||||
const arr = alloc(ABV_SIZE, id);
|
||||
checkMem();
|
||||
U32[arr + ABV_BUFFER_OFFSET >>> 2] = retain(buf);
|
||||
U32[arr + ABV_DATASTART_OFFSET >>> 2] = buf;
|
||||
U32[arr + ABV_DATALENGTH_OFFSET >>> 2] = length << align;
|
||||
var view;
|
||||
switch (align) {
|
||||
case 0: view = U8; break;
|
||||
case 1: view = U16; break;
|
||||
case 2: view = U32; break;
|
||||
case 3: view = U64; break;
|
||||
default: throw Error("unsupported align: " + align);
|
||||
}
|
||||
for (let i = 0; i < length; ++i) view[(buf >> align) + i] = values[i];
|
||||
if (info & VAL_MANAGED) for (let i = 0; i < length; ++i) retain(values[i]);
|
||||
return retain(arr);
|
||||
}
|
||||
|
||||
// /** 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 the values of an array in the module's memory by its pointer. */
|
||||
function getArray(arr) {
|
||||
checkMem();
|
||||
const id = U32[arr + ID_OFFSET >>> 2];
|
||||
const info = getInfo(id);
|
||||
if (!(info & ARRAY)) throw Error("not an array: " + id);
|
||||
const align = getAlign(VAL_ALIGN, info);
|
||||
var buf = U32[arr + ABV_DATASTART_OFFSET >>> 2];
|
||||
const length = U32[buf + SIZE_OFFSET >>> 2] >>> align;
|
||||
var view;
|
||||
switch (align) {
|
||||
// TODO: signedness/floats
|
||||
case 0: view = U8; break;
|
||||
case 1: view = U16; break;
|
||||
case 2: view = U32; break;
|
||||
case 3: view = U64; break;
|
||||
default: throw Error("unsupported align: " + align);
|
||||
}
|
||||
return Array.from(view.slice(buf >>>= align, buf + length));
|
||||
}
|
||||
|
||||
// /** 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;
|
||||
|
||||
// /** 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;
|
||||
|
||||
// /**
|
||||
// * 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;
|
||||
|
||||
// /** Gets a function by its pointer. */
|
||||
// function getFunction(ptr) {
|
||||
// return wrapFunction(table.get(ptr), setargc);
|
||||
// }
|
||||
|
||||
// baseModule.getFunction = getFunction;
|
||||
baseModule.getArray = getArray;
|
||||
|
||||
// Pull basic exports to baseModule so code in preInstantiate can use them
|
||||
baseModule.memory = baseModule.memory || memory;
|
||||
|
@ -58,3 +58,5 @@ export function calladd(fn: (a: i32, b: i32) => i32, a: i32, b: i32): i32 {
|
||||
export function dotrace(num: f64): void {
|
||||
trace("The answer is", 1, num);
|
||||
}
|
||||
|
||||
export const INT32ARRAY_ID = idof<Int32Array>();
|
||||
|
Binary file not shown.
@ -33,17 +33,19 @@ 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(module.INT32ARRAY_ID, 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(Array.from(module.getArray(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);
|
||||
// should be able to release no longer needed references
|
||||
module.__release(ptr);
|
||||
try {
|
||||
module.__release(ptr);
|
||||
assert(false);
|
||||
} catch (e) {};
|
||||
|
||||
// should be able to just call a function with variable arguments
|
||||
assert.strictEqual(module.varadd(), 3);
|
||||
|
@ -4160,7 +4160,8 @@ export function compileRTTI(compiler: Compiler): void {
|
||||
var data = new Uint8Array(size);
|
||||
writeI32(count, data, 0);
|
||||
var off = 4;
|
||||
var arrayPrototype = program.arrayPrototype;
|
||||
var abvInstance = program.arrayBufferViewInstance;
|
||||
var abvPrototype = abvInstance.prototype;
|
||||
var setPrototype = program.setPrototype;
|
||||
var mapPrototype = program.mapPrototype;
|
||||
var lastId = 0;
|
||||
@ -4168,17 +4169,16 @@ export function compileRTTI(compiler: Compiler): void {
|
||||
assert(id == lastId++);
|
||||
let flags: TypeinfoFlags = 0;
|
||||
if (instance.isAcyclic) flags |= TypeinfoFlags.ACYCLIC;
|
||||
if (instance.prototype.extends(arrayPrototype)) {
|
||||
let typeArguments = assert(instance.getTypeArgumentsTo(arrayPrototype));
|
||||
assert(typeArguments.length == 1);
|
||||
if (instance !== abvInstance && instance.extends(abvPrototype)) {
|
||||
let valueType = instance.getArrayValueType();
|
||||
flags |= TypeinfoFlags.ARRAY;
|
||||
flags |= TypeinfoFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(typeArguments[0]);
|
||||
} else if (instance.prototype.extends(setPrototype)) {
|
||||
flags |= TypeinfoFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(valueType);
|
||||
} else if (instance.extends(setPrototype)) {
|
||||
let typeArguments = assert(instance.getTypeArgumentsTo(setPrototype));
|
||||
assert(typeArguments.length == 1);
|
||||
flags |= TypeinfoFlags.SET;
|
||||
flags |= TypeinfoFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(typeArguments[0]);
|
||||
} else if (instance.prototype.extends(mapPrototype)) {
|
||||
} else if (instance.extends(mapPrototype)) {
|
||||
let typeArguments = assert(instance.getTypeArgumentsTo(mapPrototype));
|
||||
assert(typeArguments.length == 2);
|
||||
flags |= TypeinfoFlags.MAP;
|
||||
|
@ -178,6 +178,17 @@ export namespace CommonSymbols {
|
||||
export const ArrayBuffer = "ArrayBuffer";
|
||||
export const Math = "Math";
|
||||
export const Mathf = "Mathf";
|
||||
export const Int8Array = "Int8Array";
|
||||
export const Int16Array = "Int16Array";
|
||||
export const Int32Array = "Int32Array";
|
||||
export const Int64Array = "Int64Array";
|
||||
export const Uint8Array = "Uint8Array";
|
||||
export const Uint8ClampedArray = "Uint8ClampedArray";
|
||||
export const Uint16Array = "Uint16Array";
|
||||
export const Uint32Array = "Uint32Array";
|
||||
export const Uint64Array = "Uint64Array";
|
||||
export const Float32Array = "Float32Array";
|
||||
export const Float64Array = "Float64Array";
|
||||
// runtime
|
||||
export const abort = "abort";
|
||||
export const pow = "pow";
|
||||
|
@ -356,6 +356,28 @@ export class Program extends DiagnosticEmitter {
|
||||
mapPrototype: ClassPrototype;
|
||||
/** Fixed array prototype reference. */
|
||||
fixedArrayPrototype: ClassPrototype;
|
||||
/** Int8Array prototype. */
|
||||
i8ArrayPrototype: ClassPrototype;
|
||||
/** Int16Array prototype. */
|
||||
i16ArrayPrototype: ClassPrototype;
|
||||
/** Int32Array prototype. */
|
||||
i32ArrayPrototype: ClassPrototype;
|
||||
/** Int64Array prototype. */
|
||||
i64ArrayPrototype: ClassPrototype;
|
||||
/** Uint8Array prototype. */
|
||||
u8ArrayPrototype: ClassPrototype;
|
||||
/** Uint8ClampedArray prototype. */
|
||||
u8ClampedArrayPrototype: ClassPrototype;
|
||||
/** Uint16Array prototype. */
|
||||
u16ArrayPrototype: ClassPrototype;
|
||||
/** Uint32Array prototype. */
|
||||
u32ArrayPrototype: ClassPrototype;
|
||||
/** Uint64Array prototype. */
|
||||
u64ArrayPrototype: ClassPrototype;
|
||||
/** Float32Array prototype. */
|
||||
f32ArrayPrototype: ClassPrototype;
|
||||
/** Float64Array prototype. */
|
||||
f64ArrayPrototype: ClassPrototype;
|
||||
/** String instance reference. */
|
||||
stringInstance: Class;
|
||||
/** Abort function reference, if present. */
|
||||
@ -734,12 +756,14 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
// register ArrayBuffer (id=0) and String (id=1)
|
||||
// register ArrayBuffer (id=0), String (id=1), ArrayBufferView (id=2)
|
||||
assert(this.nextClassId == 0);
|
||||
this.arrayBufferInstance = this.requireClass(CommonSymbols.ArrayBuffer);
|
||||
assert(this.arrayBufferInstance.id == 0);
|
||||
this.stringInstance = this.requireClass(CommonSymbols.String);
|
||||
assert(this.stringInstance.id == 1);
|
||||
this.arrayBufferViewInstance = this.requireClass(CommonSymbols.ArrayBufferView);
|
||||
assert(this.arrayBufferViewInstance.id == 2);
|
||||
|
||||
// register classes backing basic types
|
||||
this.registerNativeTypeClass(TypeKind.I8, CommonSymbols.I8);
|
||||
@ -757,6 +781,19 @@ export class Program extends DiagnosticEmitter {
|
||||
this.registerNativeTypeClass(TypeKind.F64, CommonSymbols.F64);
|
||||
if (options.hasFeature(Feature.SIMD)) this.registerNativeTypeClass(TypeKind.V128, CommonSymbols.V128);
|
||||
|
||||
// register views but don't instantiate them yet
|
||||
this.i8ArrayPrototype = <ClassPrototype>this.require(CommonSymbols.Int8Array, ElementKind.CLASS_PROTOTYPE);
|
||||
this.i16ArrayPrototype = <ClassPrototype>this.require(CommonSymbols.Int16Array, ElementKind.CLASS_PROTOTYPE);
|
||||
this.i32ArrayPrototype = <ClassPrototype>this.require(CommonSymbols.Int32Array, ElementKind.CLASS_PROTOTYPE);
|
||||
this.i64ArrayPrototype = <ClassPrototype>this.require(CommonSymbols.Int64Array, ElementKind.CLASS_PROTOTYPE);
|
||||
this.u8ArrayPrototype = <ClassPrototype>this.require(CommonSymbols.Uint8Array, ElementKind.CLASS_PROTOTYPE);
|
||||
this.u8ClampedArrayPrototype = <ClassPrototype>this.require(CommonSymbols.Uint8ClampedArray, ElementKind.CLASS_PROTOTYPE);
|
||||
this.u16ArrayPrototype = <ClassPrototype>this.require(CommonSymbols.Uint16Array, ElementKind.CLASS_PROTOTYPE);
|
||||
this.u32ArrayPrototype = <ClassPrototype>this.require(CommonSymbols.Uint32Array, ElementKind.CLASS_PROTOTYPE);
|
||||
this.u64ArrayPrototype = <ClassPrototype>this.require(CommonSymbols.Uint64Array, ElementKind.CLASS_PROTOTYPE);
|
||||
this.f32ArrayPrototype = <ClassPrototype>this.require(CommonSymbols.Float32Array, ElementKind.CLASS_PROTOTYPE);
|
||||
this.f64ArrayPrototype = <ClassPrototype>this.require(CommonSymbols.Float64Array, ElementKind.CLASS_PROTOTYPE);
|
||||
|
||||
// resolve base prototypes of derived classes
|
||||
var resolver = this.resolver;
|
||||
for (let i = 0, k = queuedExtends.length; i < k; ++i) {
|
||||
@ -813,7 +850,6 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
// register stdlib components
|
||||
this.arrayBufferViewInstance = this.requireClass(CommonSymbols.ArrayBufferView);
|
||||
this.arrayPrototype = <ClassPrototype>this.require(CommonSymbols.Array, ElementKind.CLASS_PROTOTYPE);
|
||||
this.fixedArrayPrototype = <ClassPrototype>this.require(CommonSymbols.FixedArray, ElementKind.CLASS_PROTOTYPE);
|
||||
this.setPrototype = <ClassPrototype>this.require(CommonSymbols.Set, ElementKind.CLASS_PROTOTYPE);
|
||||
@ -3200,6 +3236,32 @@ export class Class extends TypedElement {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Gets the value type of an array. Must be an array. */
|
||||
getArrayValueType(): Type {
|
||||
var current: Class = this;
|
||||
var program = this.program;
|
||||
var abvInstance = program.arrayBufferViewInstance;
|
||||
while (current.base !== abvInstance) {
|
||||
current = assert(current.base);
|
||||
}
|
||||
switch (current.prototype) {
|
||||
case program.i8ArrayPrototype: return Type.i8;
|
||||
case program.i16ArrayPrototype: return Type.i16;
|
||||
case program.i32ArrayPrototype: return Type.i32;
|
||||
case program.i64ArrayPrototype: return Type.i64;
|
||||
case program.u8ArrayPrototype:
|
||||
case program.u8ClampedArrayPrototype: return Type.u8;
|
||||
case program.u16ArrayPrototype: return Type.u16;
|
||||
case program.u32ArrayPrototype: return Type.u32;
|
||||
case program.u64ArrayPrototype: return Type.u64;
|
||||
case program.f32ArrayPrototype: return Type.f32;
|
||||
case program.f64ArrayPrototype: return Type.f64;
|
||||
case program.arrayPrototype: return assert(this.getTypeArgumentsTo(program.arrayPrototype))[0];
|
||||
default: assert(false);
|
||||
}
|
||||
return Type.void;
|
||||
}
|
||||
|
||||
/** Tests if this class is inherently acyclic. */
|
||||
get isAcyclic(): bool {
|
||||
var acyclic = this._acyclic;
|
||||
|
@ -1,3 +1,3 @@
|
||||
export { __alloc, __realloc, __free } from "rt/tlsf";
|
||||
export { __alloc } from "rt/tlsf";
|
||||
export { __retain, __release, __collect } from "rt/pure";
|
||||
export { __instanceof, __typeinfo } from "rt";
|
||||
export { RTTI_BASE as __rtti } from "rt";
|
||||
|
@ -1,2 +1,2 @@
|
||||
export { __alloc, __realloc, __free, __retain, __release, __collect } from "rt/stub";
|
||||
export { __instanceof, __typeinfo } from "rt";
|
||||
export { __alloc, __retain, __release, __collect } from "rt/stub";
|
||||
export { RTTI_BASE as __rtti } from "rt";
|
||||
|
@ -1,2 +1,5 @@
|
||||
import { ArrayBufferView } from "arraybuffer";
|
||||
|
||||
assert(idof<ArrayBuffer>() == 0);
|
||||
assert(idof<String>() == 1);
|
||||
assert(idof<ArrayBufferView>() == 2);
|
||||
|
@ -16,7 +16,7 @@
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 1
|
||||
i32.const 3
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
@ -28,7 +28,19 @@
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 2
|
||||
i32.const 4
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
end
|
||||
i32.const 2
|
||||
i32.const 2
|
||||
i32.eq
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
i32.const 24
|
||||
i32.const 5
|
||||
i32.const 0
|
||||
call $~lib/builtins/abort
|
||||
unreachable
|
||||
|
Loading…
x
Reference in New Issue
Block a user