Skip to content

Commit

Permalink
Finished support for import object wrapping
Browse files Browse the repository at this point in the history
  • Loading branch information
torch2424 committed Sep 8, 2019
1 parent f8301a0 commit 8b12462
Show file tree
Hide file tree
Showing 9 changed files with 409 additions and 78 deletions.
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
# asbind

Library to handle passing high-level data structures between AssemblyScript and JavaScript

# Notes
# Compatibility notes

Supported types (params and returns on exported functions FROM Assemblyscript):

Strings, TypedArrays

Supported types (params on import object functions. RETURNS NOT SUPPORTED):

Strings, TypedArrays

# API Planning Notes

Maybe not asbind? Yes, as bind it matches up with what wasm bndgen says

Only supports the `--runtime full`, and `--runtime stub` flag. And should, because anything else would mean that you DO NOT want to create objects externally to your wasm module.
Only supports the `--runtime full`, and `--runtime stub` flag. And should, because anything else would mean that you DO NOT want to create objects externally to your wasm module.

Simply need to wrap the docs from: https://docs.assemblyscript.org/details/runtime and we should be good to go!

Expand All @@ -25,7 +36,7 @@ wasmModule.exports = asbind.bind(wasmModule.exports);
```

```typescript
export * from "asbind"
export * from "asbind";

// Other stuff
```
Expand Down
49 changes: 49 additions & 0 deletions lib/import-object.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import SUPPORTED_TYPES from "./supported-types";

// Use instance of to scan the importObject for Asbinded Import functions,
// That are then replaced with the actual function that wraps around the import and does the appropriate stuff
export class AsbindImportFunction {
constructor(importFunction) {
this.importFunction = importFunction;
}

applyImportFunction(wasmExports, functionArgumentRefs) {
if (!wasmExports) {
throw new Error("Could not access the instantiated Wasm Export");
}

// Get the types from the passed references in AS
const functionArguments = [];
functionArgumentRefs.forEach(ref => {
// Find our supported type
let supportedType = undefined;
Object.keys(SUPPORTED_TYPES).some(key => {
if (SUPPORTED_TYPES[key].isTypeFromReference(wasmExports, ref)) {
supportedType = SUPPORTED_TYPES[key];
return true;
}

return false;
});

if (!supportedType) {
throw new Error(
`The reference, ${ref}, passed to the import object function is not a supported type by asbind`
);
}
functionArguments.push(supportedType.getValueFromRef(wasmExports, ref));
});

// Call the import function
this.importFunction.apply(null, functionArguments);

// TODO: Returning from Import functions is not supported by asbind :(
}
}

// Fuction that takes in an importFunction to be wrapped,
// And the type parameters, and return parameter of the function
export function asbindWrapImportObjectFunction(importFunction) {
// Return our AsbindImportFunction
return new AsbindImportFunction(importFunction);
}
54 changes: 54 additions & 0 deletions lib/instantiate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Wrapper around the loader instantiate
import * as loader from "assemblyscript/lib/loader";
import { AsbindImportFunction } from "./import-object";

export async function asbindInstantiate(source, importObject) {
let wasmInstanceExports;

// Need to traverse the importObject and replace all wrapped asbind import functions
const traverseObjectAndWrapAsbindImports = function(baseObject) {
if (!baseObject) {
return;
}

Object.keys(baseObject).forEach(baseObjectKey => {
if (baseObject[baseObjectKey] instanceof AsbindImportFunction) {
let asbindImportFunction = baseObject[baseObjectKey];
// Wrap the asbindImportFunction as a function that passes in the argument references,
// As well as the instantiated exports of the wasm module
baseObject[baseObjectKey] = function() {
let functionArgumentRefs = [];
for (let i = 0; i < arguments.length; i++) {
functionArgumentRefs.push(arguments[i]);
}
asbindImportFunction.applyImportFunction(
wasmInstanceExports,
functionArgumentRefs
);
};
} else if (typeof baseObject[baseObjectKey] === "object") {
traverseObjectAndWrapAsbindImports(baseObject[baseObjectKey]);
}
});
};
traverseObjectAndWrapAsbindImports(importObject);

// Use the correct loader instantiation
// https://github.com/AssemblyScript/assemblyscript/tree/master/lib/loader#api
if (source instanceof WebAssembly.Module) {
wasmInstanceExports = loader.instantiate(source, importObject);
} else if (source instanceof Uint8Array) {
wasmInstanceExports = loader.instantiateBuffer(source, importObject);
} else if (source instanceof Response) {
wasmInstanceExports = await loader.instantiateStreaming(
source,
importObject
);
} else {
throw new Error(
"The type of value passed as the Wasm source is not supported"
);
}

return wasmInstanceExports;
}
11 changes: 4 additions & 7 deletions lib/lib.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import * as loader from "assemblyscript/lib/loader";
import { asbindInstantiate } from "./instantiate";
import { asbindCall, asbindApply } from "./function";
import { asbindWrapImportObjectFunction } from "./import-object";
import packageJson from "../package.json";

const asbind = {
// General asbind version
version: packageJson.version,

// Required Loader APIs
instantiate: loader.instantiate,
instantiateBuffer: loader.instantiateBuffer,
instantiateStreaming: loader.instantiateStreaming,
demangle: loader.demangle,

// Our APIs
instantiate: asbindInstantiate,
wrapImportObjectFunction: asbindWrapImportObjectFunction,
call: asbindCall,
apply: asbindApply
};
Expand Down
16 changes: 8 additions & 8 deletions lib/supported-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const SUPPORTED_TYPES = {
);
},
getValueFromRef: (wasmExports, responseRef) => {
return wasmExports.__getArray(responseRef);
return Int8Array.from(wasmExports.__getArray(responseRef));

This comment has been minimized.

Copy link
@MaxGraey

MaxGraey Sep 8, 2019

Just use return wasmExports.__getInt8Array(responseRef), wasmExports.__getUint8Array, wasmExports.__getFloat32Array and etc... They are blazing fast

This comment has been minimized.

Copy link
@torch2424

torch2424 Sep 9, 2019

Author Owner

Oh nice! Definitely will do that! Thank you! 😄

}
},
UINT8ARRAY: {
Expand All @@ -42,7 +42,7 @@ const SUPPORTED_TYPES = {
);
},
getValueFromRef: (wasmExports, responseRef) => {
return wasmExports.__getArray(responseRef);
return Uint8Array.from(wasmExports.__getArray(responseRef));
}
},
INT16ARRAY: {
Expand All @@ -58,7 +58,7 @@ const SUPPORTED_TYPES = {
);
},
getValueFromRef: (wasmExports, responseRef) => {
return wasmExports.__getArray(responseRef);
return Int16Array.from(wasmExports.__getArray(responseRef));
}
},
UINT16ARRAY: {
Expand All @@ -74,7 +74,7 @@ const SUPPORTED_TYPES = {
);
},
getValueFromRef: (wasmExports, responseRef) => {
return wasmExports.__getArray(responseRef);
return Uint16Array.from(wasmExports.__getArray(responseRef));
}
},
INT32ARRAY: {
Expand All @@ -90,7 +90,7 @@ const SUPPORTED_TYPES = {
);
},
getValueFromRef: (wasmExports, responseRef) => {
return wasmExports.__getArray(responseRef);
return Int32Array.from(wasmExports.__getArray(responseRef));
}
},
UINT32ARRAY: {
Expand All @@ -106,7 +106,7 @@ const SUPPORTED_TYPES = {
);
},
getValueFromRef: (wasmExports, responseRef) => {
return wasmExports.__getArray(responseRef);
return Uint32Array.from(wasmExports.__getArray(responseRef));
}
},
FLOAT32ARRAY: {
Expand All @@ -125,7 +125,7 @@ const SUPPORTED_TYPES = {
);
},
getValueFromRef: (wasmExports, responseRef) => {
return wasmExports.__getArray(responseRef);
return Float32Array.from(wasmExports.__getArray(responseRef));
}
},
FLOAT64ARRAY: {
Expand All @@ -144,7 +144,7 @@ const SUPPORTED_TYPES = {
);
},
getValueFromRef: (wasmExports, responseRef) => {
return wasmExports.__getArray(responseRef);
return Float64Array.from(wasmExports.__getArray(responseRef));
}
}
};
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"dev": "npx run-p lib:watch lib:test:watch",
"test": "npx mocha",
"lint": "npx prettier --write **/*.js **/*.ts **/*.json !build/**/* !dist/**/*",
"lib:watch": "npx chokidar \"lib/**/*\" -c \"npx run-s build:wasm build:lib test\"",
"lib:test:watch": "npx chokidar \"test/**/*.js\" \"test/**/*.ts\" -c \"npx run-s build:test test\"",
"lib:watch": "npx chokidar \"lib/**/*\" -c \"npx run-s lib:wasm:build lib:js:build test\"",
"lib:test:watch": "npx chokidar \"test/**/*.js\" \"test/**/*.ts\" -c \"npx run-s lib:test:build test\"",
"lib:wasm:build": "npx run-s lib:wasm:build:debug lib:wasm:build:optimized lib:wasm:build:cp",
"lib:wasm:build:debug": "npx asc lib/assembly/asbind.ts -b dist/asbind.debug.wasm -t dist/asbind.debug.wat --sourceMap --validate --debug --runtime full",
"lib:wasm:build:optimized": "npx asc lib/assembly/asbind.ts -b dist/asbind.wasm -t dist/asbind.wat --sourceMap --validate --optimize --runtime full",
Expand Down
54 changes: 54 additions & 0 deletions test/assembly/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,57 @@ export function mapFloat32Array(array: Float32Array): Float32Array {
export function mapFloat64Array(array: Float64Array): Float64Array {
return array.map((value: f64) => value * 2);
}

// NOTE: Asbind does not support return types on import object functions
declare function testImportString(value: string): void;
export function callTestImportString(value: string): void {
testImportString(value);
}

declare function testImportTwoStrings(valueOne: string, valueTwo: string): void;
export function callTestImportTwoStrings(
valueOne: string,
valueTwo: string
): void {
testImportTwoStrings(valueOne, valueTwo);
}

declare function testImportInt8Array(value: Int8Array): void;
export function callTestImportInt8Array(value: Int8Array): void {
testImportInt8Array(value);
}

declare function testImportUint8Array(value: Uint8Array): void;
export function callTestImportUint8Array(value: Uint8Array): void {
testImportUint8Array(value);
}

declare function testImportInt16Array(value: Int16Array): void;
export function callTestImportInt16Array(value: Int16Array): void {
testImportInt16Array(value);
}

declare function testImportUint16Array(value: Uint16Array): void;
export function callTestImportUint16Array(value: Uint16Array): void {
testImportUint16Array(value);
}

declare function testImportInt32Array(value: Int32Array): void;
export function callTestImportInt32Array(value: Int32Array): void {
testImportInt32Array(value);
}

declare function testImportUint32Array(value: Uint32Array): void;
export function callTestImportUint32Array(value: Uint32Array): void {
testImportUint32Array(value);
}

declare function testImportFloat32Array(value: Float32Array): void;
export function callTestImportFloat32Array(value: Float32Array): void {
testImportFloat32Array(value);
}

declare function testImportFloat64Array(value: Float64Array): void;
export function callTestImportFloat64Array(value: Float64Array): void {
testImportFloat64Array(value);
}
Binary file modified test/assembly/test.wasm
Binary file not shown.
Loading

0 comments on commit 8b12462

Please sign in to comment.