Skip to content

Commit

Permalink
Update loader with what we've learned (#810)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcodeIO authored Sep 2, 2019
1 parent b479950 commit bc48898
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 237 deletions.
127 changes: 38 additions & 89 deletions lib/loader/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,93 +30,23 @@ API

Besides demangling classes exported from your entry file to a handy object structure one can use like JS objects, instances are automatically populated with useful utility:

* **I8**: `Int8Array`<br />
An 8-bit signed integer view on the memory.

```ts
var value = module.I8[ptr];
```

* **U8**: `Uint8Array`<br />
An 8-bit unsigned integer view on the memory.

```ts
var value = module.U8[ptr];
```

* **I16**: `Int16Array`<br />
A 16-bit signed integer view on the memory.

```ts
var value = module.I16[ptr >>> 1];
```

* **U16**: `Uint16Array`<br />
A 16-bit unsigned integer view on the memory.

```ts
var value = module.U16[ptr >>> 1];
```

* **I32**: `Int32Array`<br />
A 32-bit signed integer view on the memory.

```ts
var value = module.I32[ptr >>> 2];
```

* **U32**: `Uint32Array`<br />
A 32-bit unsigned integer view on the memory.

```ts
var value = module.U32[ptr >>> 2];
```

* **I64**: `BigInt64Array`<br />
A 64-bit signed integer view on the memory, if supported by the VM.

```ts
var value = module.I64[ptr >>> 3];
```

* **U64**: `BigUint64Array`<br />
A 64-bit unsigned integer view on the memory, if supported by the VM.

```ts
var value = module.U64[ptr >>> 3];
```

* **F32**: `Float32Array`<br />
A 32-bit float view on the memory.

```ts
var value = module.I32[ptr >>> 2];
```

* **F64**: `Float64Array`<br />
A 64-bit float view on the memory.

```ts
var value = module.F64[ptr >>> 3];
```

* **__start**(): `void`<br />
Explicit start function if the `--explicitStart` option is used. Must be called before any other exports if present.

* **__allocString**(str: `string`): `number`<br />
Allocates a new string in the module's memory and returns a reference (pointer) to it.

```ts
var ref = module.__retain(module.__allocString("hello world"));
var ptr = module.__retain(module.__allocString("hello world"));
...
module.__release(ref);
module.__release(ptr);
```

* **__getString**(ref: `number`): `string`<br />
* **__getString**(ptr: `number`): `string`<br />
Reads (copies) the value of a string from the module's memory.

```ts
var str = module.__getString(ref);
var str = module.__getString(ptr);
...
```

Expand All @@ -125,44 +55,63 @@ Besides demangling classes exported from your entry file to a handy object struc
Automatically retains interior pointers. 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 id is an `export const INT32ARRAY_ID = idof<Int32Array>()`. When done with the array, make sure to release it.

```ts
var ref = module.__retain(module.__allocArray(module.INT32ARRAY, [1, 2, 3]));
var ptr = module.__retain(module.__allocArray(module.INT32ARRAY, [1, 2, 3]));
...
module.__release(ref);
module.__release(ptr);
```

* **__getArray**(ref: `number`): `number[]`<br />
* **__getArray**(ptr: `number`): `number[]`<br />
Reads (copies) the values of an array from the module's memory.

```ts
var arr = module.__getArray(ref);
var arr = module.__getArray(ptr);
...
```

* **__getArrayView**(ref: `number`): `TypedArray`<br />
* **__getArrayView**(ptr: `number`): `TypedArray`<br />
Gets a view on the values of an array in the module's memory. This differs from `__getArray` in that the data isn't copied but remains *live* in both directions. That's faster but also unsafe because if the array grows or becomes released, the view will no longer represent the correct memory region and modifying its values in this state will most likely corrupt memory. Use, but use with care.

* **__retain**(ref: `number`): `number`<br />
Retains a reference externally, making sure that it doesn't become collected prematurely. Returns the reference.
If the type of the array is known beforehand, the following even faster and even more unsafe helpers can be used that don't do any type checking:

**__getInt8Array**(ptr: `number`): `Int8Array`<br />
**__getUint8Array**(ptr: `number`): `Uint8Array`<br />
**__getUint8ClampedArray**(ptr: `number`): `Uint8ClampedArray`<br />
**__getInt16Array**(ptr: `number`): `Int16Array`<br />
**__getUint16Array**(ptr: `number`): `Uint16Array`<br />
**__getInt32Array**(ptr: `number`): `Int32Array`<br />
**__getUint32Array**(ptr: `number`): `Uint32Array`<br />
**__getInt64Array**(ptr: `number`): `BigInt64Array`<br />
**__getUint64Array**(ptr: `number`): `BigUint64Array`<br />
**__getFloat32Array**(ptr: `number`): `Float32Array`<br />
**__getFloat64Array**(ptr: `number`): `Float64Array`

* **__getArrayBuffer**(ptr: `number`): `ArrayBuffer`<br />
Reads (copies) the data of an ArrayBuffer from the module's memory.

* **__retain**(ptr: `number`): `number`<br />
Retains a reference to a managed object externally, making sure that it doesn't become collected prematurely. Returns the pointer.

* **__release**(ref: `number`): `void`<br />
Releases a previously retained reference to an object, allowing the runtime to collect it once its reference count reaches zero.
* **__release**(ptr: `number`): `void`<br />
Releases a previously retained reference to a managed object, allowing the runtime to collect it once its reference count reaches zero.

* **__alloc**(size: `number`, id: `number`): `number`<br />
Allocates an instance of the class represented by the specified id. If you are using `MyClass` for example, the best way to know the id and the necessary size is an `export const MYCLASS_ID = idof<MyClass>()` and an `export const MYCLASS_SIZE = offsetof<MyClass>()`. Afterwards, use the respective views to assign values to the class's memory while making sure to retain interior references to other managed objects once. When done with the class, make sure to release it, which will automatically release any interior references once the class becomes collected.

```ts
var ref = module.__retain(module.__alloc(module.MYCLASS_SIZE, module.MYCLASS_ID));
F32[ref + MYCLASS_BASICFIELD1_OFFSET >>> 2] = field1_value_f32;
U32[ref + MYCLASS_MANAGEDFIELD2_OFFSET >>> 2] = module.__retain(field2_value_ref);
var ptr = module.__retain(module.__alloc(module.MYCLASS_SIZE, module.MYCLASS_ID));
const F32 = new Float32Array(module.memory.buffer);
F32[ptr + MYCLASS_BASICFIELD1_OFFSET >>> 2] = field1_value_f32;
const U32 = new Uint32Array(module.memory.buffer);
U32[ptr + MYCLASS_MANAGEDFIELD2_OFFSET >>> 2] = module.__retain(field2_value_ptr);
...
module.__release(ref);
module.__release(ptr);
```

* **__instanceof**(ref: `number`, baseId: `number`): `boolean`<br />
* **__instanceof**(ptr: `number`, baseId: `number`): `boolean`<br />
Tests whether an object is an instance of the class represented by the specified base id.

```ts
if (module.__instanceof(ref, module.MYCLASS_ID)) {
if (module.__instanceof(ptr, module.MYCLASS_ID)) {
...
}
```
Expand Down
72 changes: 32 additions & 40 deletions lib/loader/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// <reference lib="esnext.bigint" />

import "@types/webassembly-js-api";

/** WebAssembly imports with two levels of nesting. */
Expand All @@ -19,66 +21,56 @@ type TypedArray
| Int32Array
| Uint32Array
| Float32Array
| Float64Array;
| Float64Array
| BigInt64Array
| BigUint64Array;

/** Utility mixed in by the loader. */
interface ASUtil {
/** An 8-bit signed integer view on the memory. */
readonly I8: Uint8Array;
/** An 8-bit unsigned integer view on the memory. */
readonly U8: Uint8Array;
/** A 16-bit signed integer view on the memory. */
readonly I16: Uint16Array;
/** A 16-bit unsigned integer view on the memory. */
readonly U16: Uint16Array;
/** A 32-bit signed integer view on the memory. */
readonly I32: Uint32Array;
/** A 32-bit unsigned integer view on the memory. */
readonly U32: Uint32Array;
/** A 64-bit signed integer view on the memory. */
readonly I64: any; // BigInt64Array
/** A 64-bit unsigned integer vieww on the memory. */
readonly U64: any; // BigUint64Array
/** A 32-bit float view on the memory. */
readonly F32: Float32Array;
/** A 64-bit float view on the memory. */
readonly F64: Float64Array;
/** 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;
/** Reads (copies) the value of a string from the module's memory. */
__getString(ref: number): string;
__getString(ptr: number): string;
/** Allocates a new array in the module's memory and returns a reference (pointer) to it. */
__allocArray(id: number, values: number[]): number;
/** Reads (copies) the values of an array from the module's memory. */
__getArray(ref: number): number[];
__getArray(ptr: number): number[];
/** Gets a view on the values of an array in the module's memory. */
__getArrayView(ref: number): TypedArray;
/** Reads (copies) the values of Uint8Array from the module's memory. */
__getUint8Array(ref: number): Uint8Array;
__getArrayView(ptr: number): TypedArray;
/** Reads (copies) the values of Int8Array from the module's memory. */
__getInt8Array(ref: number): Int8Array;
/** Reads (copies) the values of Uint16Array from the module's memory. */
__getUint16Array(ref: number): Uint16Array;
__getInt8Array(ptr: number): Int8Array;
/** Reads (copies) the values of Uint8Array from the module's memory. */
__getUint8Array(ptr: number): Uint8Array;
/** Reads (copies) the values of Uint8Array from the module's memory. */
__getUint8ClampedArray(ptr: number): Uint8ClampedArray;
/** Reads (copies) the values of Int16Array from the module's memory. */
__getInt16Array(ref: number): Int16Array;
__getInt16Array(ptr: number): Int16Array;
/** Reads (copies) the values of Uint16Array from the module's memory. */
__getUint16Array(ptr: number): Uint16Array;
/** Reads (copies) the values of Int32Array from the module's memory. */
__getInt32Array(ptr: number): Int32Array;
/** Reads (copies) the values of Uint32Array from the module's memory. */
__getUint32Array(ref: number): Uint32Array;
__getUint32Array(ptr: number): Uint32Array;
/** Reads (copies) the values of Int32Array from the module's memory. */
__getInt32Array(ref: number): Int32Array;
__getInt64Array(ptr: number): BigInt32Array;
/** Reads (copies) the values of Uint32Array from the module's memory. */
__getUint64Array(ptr: number): BigUint32Array;
/** Reads (copies) the values of Float32Array from the module's memory. */
__getFloat32Array(ref: number): Float32Array;
__getFloat32Array(ptr: number): Float32Array;
/** Reads (copies) the values of Float64Array from the module's memory. */
__getFloat64Array(ref: number): Float64Array;
/** Retains a reference externally, making sure that it doesn't become collected prematurely. Returns the reference. */
__retain(ref: number): number;
/** Releases a previously retained reference to an object, allowing the runtime to collect it once its reference count reaches zero. */
__release(ref: number): void;
__getFloat64Array(ptr: number): Float64Array;
/** Reads (copies) the data of an ArrayBuffer from the module's memory. */
__getArrayBuffer(ptr: number): ArrayBuffer;
/** 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;
/** Allocates an instance of the class represented by the specified id. */
__alloc(size: number, id: number): number;
/** Tests whether an object is an instance of the class represented by the specified base id. */
__instanceof(ref: number, baseId: number): boolean;
/** 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. */
__collect(): void;
}
Expand Down
Loading

0 comments on commit bc48898

Please sign in to comment.