mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 15:12:12 +00:00
Add initial newArray and getArray helpers to loader
Essentially creates an unmanaged typed array in memory that one can work with and free again respectively obtain from the AS side. No support for GC or generic arrays yet, and is likely to change substentially once WASM GC becomes a thing.
This commit is contained in:
parent
16d1a833dd
commit
9c770d801e
2
dist/asc.js
vendored
2
dist/asc.js
vendored
File diff suppressed because one or more lines are too long
2
dist/asc.js.map
vendored
2
dist/asc.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js
vendored
2
dist/assemblyscript.js
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js.map
vendored
2
dist/assemblyscript.js.map
vendored
File diff suppressed because one or more lines are too long
@ -61,7 +61,7 @@ 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. Requires `allocate_memory` to be exported from your module's entry file, i.e.:
|
||||
Allocates a new string in the module's memory and returns its pointer. Requires `memory.allocate` to be exported from your module's entry file, i.e.:
|
||||
|
||||
```js
|
||||
import "allocator/tlsf";
|
||||
@ -71,6 +71,18 @@ Instances are automatically populated with useful utility:
|
||||
* **getString**(ptr: `number`): `string`<br />
|
||||
Gets 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.
|
||||
|
||||
* **newArray**(ctor: `TypedArrayConstructor`, length: `number`): `number`<br />
|
||||
Creates a typed array in the module's memory and returns 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.
|
||||
|
||||
<sup>1</sup> This feature has not yet landed in any VM as of this writing.
|
||||
|
||||
Examples
|
||||
@ -125,7 +137,7 @@ myModule.F64[ptrToFloat64 >>> 3] = newValue;
|
||||
var str = "Hello world!";
|
||||
var ptr = module.newString(str);
|
||||
|
||||
// Disposing a string that is no longer needed (requires free_memory to be exported)
|
||||
// Disposing a string that is no longer needed (requires memory.free to be exported)
|
||||
module.memory.free(ptr);
|
||||
|
||||
// Obtaining a string, i.e. as returned by an export
|
||||
|
28
lib/loader/index.d.ts
vendored
28
lib/loader/index.d.ts
vendored
@ -10,6 +10,26 @@ interface ImportsObject {
|
||||
}
|
||||
}
|
||||
|
||||
type TypedArray
|
||||
= Int8Array
|
||||
| Uint8Array
|
||||
| Int16Array
|
||||
| Uint16Array
|
||||
| Int32Array
|
||||
| Uint32Array
|
||||
| Float32Array
|
||||
| Float64Array;
|
||||
|
||||
type TypedArrayConstructor
|
||||
= Int8ArrayConstructor
|
||||
| Uint8ArrayConstructor
|
||||
| Int16ArrayConstructor
|
||||
| Uint16ArrayConstructor
|
||||
| Int32ArrayConstructor
|
||||
| Uint32ArrayConstructor
|
||||
| Float32ArrayConstructor
|
||||
| Float32ArrayConstructor;
|
||||
|
||||
/** Utility mixed in by the loader. */
|
||||
interface ASUtil {
|
||||
/** An 8-bit signed integer view on the memory. */
|
||||
@ -36,6 +56,14 @@ interface ASUtil {
|
||||
newString(str: string): number;
|
||||
/** Gets a string from the module's memory by its pointer. */
|
||||
getString(ptr: number): string;
|
||||
/** Copies a typed array into the module's memory and returns its pointer. */
|
||||
newArray(view: TypedArray, length?: number): number;
|
||||
/** Creates a typed array in the module's memory and returns its pointer. */
|
||||
newArray(ctor: TypedArrayConstructor, length: number, unsafe?: boolean): number;
|
||||
/** Gets a view on a typed array in the module's memory by its pointer. */
|
||||
getArray(ctor: TypedArrayConstructor, ptr: number): TypedArray;
|
||||
/** Frees a typed array in the module's memory. Must not be accessed anymore afterwards. */
|
||||
freeArray(ptr: number): void;
|
||||
}
|
||||
|
||||
/** Instantiates an AssemblyScript module using the specified imports. */
|
||||
|
@ -17,6 +17,9 @@ function instantiate(module, imports) {
|
||||
// Instantiate the module and obtain its (flat) exports
|
||||
var instance = new WebAssembly.Instance(module, imports);
|
||||
var exports = instance.exports;
|
||||
var memory_allocate = exports["memory.allocate"];
|
||||
var memory_fill = exports["memory.fill"];
|
||||
var memory_free = exports["memory.free"];
|
||||
|
||||
// Provide views for all sorts of basic values
|
||||
var mem, I8, U8, I16, U16, I32, U32, F32, F64, I64, U64;
|
||||
@ -45,7 +48,7 @@ function instantiate(module, imports) {
|
||||
/** Allocates a new string in the module's memory and returns its pointer. */
|
||||
function newString(str) {
|
||||
var dataLength = str.length;
|
||||
var ptr = exports["memory.allocate"](4 + (dataLength << 1));
|
||||
var ptr = memory_allocate(4 + (dataLength << 1));
|
||||
var dataOffset = (4 + ptr) >>> 1;
|
||||
checkMem();
|
||||
U32[ptr >>> 2] = dataLength;
|
||||
@ -71,6 +74,62 @@ function instantiate(module, imports) {
|
||||
return parts.join("") + String.fromCharCode.apply(String, U16.subarray(dataOffset, dataOffset + dataRemain));
|
||||
}
|
||||
|
||||
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(mem, 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;
|
||||
}
|
||||
|
||||
/** 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(mem, buf + 8 + byteOffset, (byteLength - byteOffset) / elementSize);
|
||||
}
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
||||
// Demangle exports and provide the usual utility on the prototype
|
||||
return demangle(exports, {
|
||||
get I8() { checkMem(); return I8; },
|
||||
@ -84,7 +143,10 @@ function instantiate(module, imports) {
|
||||
get F32() { checkMem(); return F32; },
|
||||
get F64() { checkMem(); return F64; },
|
||||
newString,
|
||||
getString
|
||||
getString,
|
||||
newArray,
|
||||
getArray,
|
||||
freeArray
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import "allocator/arena";
|
||||
import "allocator/tlsf";
|
||||
|
||||
export { memory };
|
||||
|
||||
@ -44,3 +44,9 @@ export class Car {
|
||||
memory.free(changetype<usize>(this));
|
||||
}
|
||||
}
|
||||
|
||||
export function sum(arr: Int32Array): i32 {
|
||||
var v = 0;
|
||||
for (let i = 0, k = arr.length; i < k; ++i) v += arr[i];
|
||||
return v;
|
||||
}
|
||||
|
Binary file not shown.
@ -33,3 +33,16 @@ var str = "Hello world!𤭢";
|
||||
var ptr = module.newString(str);
|
||||
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);
|
||||
|
||||
// should be able to get a view on an internal typed array
|
||||
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);
|
||||
|
@ -6523,6 +6523,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
// if present, check that the constructor is compatible with object literals
|
||||
var ctor = classReference.constructorInstance;
|
||||
if (ctor) {
|
||||
// TODO: if the constructor requires parameters, check whether these are given as part of the
|
||||
// object literal and use them to call the ctor while not generating a store.
|
||||
if (ctor.signature.requiredParameters) {
|
||||
this.error(
|
||||
DiagnosticCode.Constructor_of_class_0_must_not_require_any_arguments,
|
||||
|
Loading…
x
Reference in New Issue
Block a user