From 69e8c0476b1b24352ce933c6d81828ba56b3ce9c Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 1 Feb 2020 17:29:54 +0100 Subject: [PATCH] Derive ids from RTTI --- lib/asbind-instance.js | 57 +++++++++++++++++++++++ lib/assembly/as-bind.ts | 22 ++++----- lib/bind-function.js | 24 +++++++--- lib/supported-ref-types.js | 92 +++++++++++++++----------------------- 4 files changed, 122 insertions(+), 73 deletions(-) diff --git a/lib/asbind-instance.js b/lib/asbind-instance.js index 94083e7..1f05e92 100644 --- a/lib/asbind-instance.js +++ b/lib/asbind-instance.js @@ -28,9 +28,63 @@ const traverseObjectAndRunCallbackForFunctions = ( }); }; +// see: assemblyscript/std/assembly/shared/typeinfo.ts +const deriveIdsFromRtti = (unboundExports, ids) => { + const ARRAY = 1 << 1; + const VALUE_ALIGN_SHIFT = 5; + const VALUE_SIGNED = 1 << 10; + const VALUE_FLOAT = 1 << 11; + + const rtti = new Uint32Array( + unboundExports.memory.buffer, + unboundExports.__rtti_base + ); + + for (let i = 3, k = rtti[0]; i < k; ++i) { + const flags = rtti[1 + (i << 1)]; + const base = rtti[2 + (i << 1)]; + if (base === ids.ARRAYBUFFERVIEW && !(flags & ARRAY)) { + // typed array + const align = 31 - Math.clz32((flags >>> VALUE_ALIGN_SHIFT) & 31); + const signed = Boolean(flags & VALUE_SIGNED); + const float = Boolean(flags & VALUE_FLOAT); + switch (align) { + case 0: { + if (signed) ids.INT8ARRAY = i; + else ids.UINT8ARRAY = i; + break; + } + case 1: { + if (signed) ids.INT16ARRAY = i; + else ids.UINT16ARRAY = i; + break; + } + case 2: { + if (float) ids.FLOAT32ARRAY = i; + else if (signed) ids.INT32ARRAY = i; + else ids.UINT32ARRAY = i; + break; + } + case 3: { + if (float) ids.FLOAT64ARRAY = i; + else if (signed) ids.INT64ARRAY = i; + else ids.UINT64ARRAY = i; + break; + } + } + } + } +}; + export default class AsbindInstance { constructor() { this.unboundExports = {}; + this.ids = { + // Ids of fundamental classes are fixed + ARRAYBUFFER: 0, + STRING: 1, + ARRAYBUFFERVIEW: 2 + }; this.exports = {}; this.importObject = {}; } @@ -58,6 +112,9 @@ export default class AsbindInstance { // Instantiate the module through the loader this.unboundExports = await asbindInstantiate(source, this.importObject); + // Derive runtime ids from RTTI + deriveIdsFromRtti(this.unboundExports, this.ids); + // Wrap appropriate the appropriate export functions this.exports = {}; Object.keys(this.unboundExports).forEach(unboundExportKey => { diff --git a/lib/assembly/as-bind.ts b/lib/assembly/as-bind.ts index 86287e4..eff2d3a 100644 --- a/lib/assembly/as-bind.ts +++ b/lib/assembly/as-bind.ts @@ -1,19 +1,19 @@ // Neccessary bootstrapping for asbind // Strings -export const __asbind_String_ID = idof(); +// export const __asbind_String_ID = idof(); // ArrayBuffers // TODO: Maybe support these? -export const __asbind_ArrayBuffer_ID = idof(); -export const __asbind_ArrayBufferView_ID = idof(); +// export const __asbind_ArrayBuffer_ID = idof(); +// export const __asbind_ArrayBufferView_ID = idof(); // Typed Arrays -export const __asbind_Int8Array_ID = idof(); -export const __asbind_Uint8Array_ID = idof(); -export const __asbind_Int16Array_ID = idof(); -export const __asbind_Uint16Array_ID = idof(); -export const __asbind_Int32Array_ID = idof(); -export const __asbind_Uint32Array_ID = idof(); -export const __asbind_Float32Array_ID = idof(); -export const __asbind_Float64Array_ID = idof(); +// export const __asbind_Int8Array_ID = idof(); +// export const __asbind_Uint8Array_ID = idof(); +// export const __asbind_Int16Array_ID = idof(); +// export const __asbind_Uint16Array_ID = idof(); +// export const __asbind_Int32Array_ID = idof(); +// export const __asbind_Uint32Array_ID = idof(); +// export const __asbind_Float32Array_ID = idof(); +// export const __asbind_Float64Array_ID = idof(); diff --git a/lib/bind-function.js b/lib/bind-function.js index da29b32..c5e934f 100644 --- a/lib/bind-function.js +++ b/lib/bind-function.js @@ -31,6 +31,7 @@ export function bindImportFunction( let functionThis = importObject; const boundImport = function() { const exports = asbindInstance.unboundExports; + const ids = asbindInstance.ids; // Get the 'this' of the function if (functionThis === importObject) { @@ -59,7 +60,9 @@ export function bindImportFunction( SUPPORTED_REF_TYPES[functionThis.cachedArgTypes[argIndex].key]; } else { Object.keys(SUPPORTED_REF_TYPES).some(key => { - if (SUPPORTED_REF_TYPES[key].isTypeFromReference(exports, arg)) { + if ( + SUPPORTED_REF_TYPES[key].isTypeFromReference(exports, arg, ids[key]) + ) { supportedType = SUPPORTED_REF_TYPES[key]; if (functionThis.shouldCacheTypes) { functionThis.cachedArgTypes[argIndex] = { @@ -102,6 +105,7 @@ export function bindImportFunction( // abindInstance.exports object, to be wrapped and then re-assigned to the asbindInstance.exports. export function bindExportFunction(asbindInstance, exportFunctionKey) { const exports = asbindInstance.unboundExports; + const ids = asbindInstance.ids; const originalExport = exports[exportFunctionKey]; validateExportsAndFunction(exports, originalExport); @@ -138,6 +142,7 @@ export function bindExportFunction(asbindInstance, exportFunctionKey) { // A supported reference type is being passed, // Find our supported type let supportedType = undefined; + let id = undefined; // Check if we already cached the type if ( @@ -145,8 +150,9 @@ export function bindExportFunction(asbindInstance, exportFunctionKey) { functionThis.cachedArgTypes[argIndex] && functionThis.cachedArgTypes[argIndex].type === "ref" ) { - supportedType = - SUPPORTED_REF_TYPES[functionThis.cachedArgTypes[argIndex].key]; + const key = functionThis.cachedArgTypes[argIndex].key; + supportedType = SUPPORTED_REF_TYPES[key]; + id = ids[key]; } else { // Find the type, and error if we could not Object.keys(SUPPORTED_REF_TYPES).some(key => { @@ -158,6 +164,7 @@ export function bindExportFunction(asbindInstance, exportFunctionKey) { key }; } + id = ids[key]; return true; } @@ -169,9 +176,14 @@ export function bindExportFunction(asbindInstance, exportFunctionKey) { `The argument, ${arg}, is not a supported type by asbind` ); } + if (id === undefined) { + throw new Error( + `The argument, ${arg}, is a supported type, but not present in the binary` + ); + } } - argumentsWithReplacedRefs.push(supportedType.getRef(exports, arg)); + argumentsWithReplacedRefs.push(supportedType.getRef(exports, arg, id)); refIndexes.push(argIndex); }); @@ -206,9 +218,11 @@ export function bindExportFunction(asbindInstance, exportFunctionKey) { // We need to find / cache the type Object.keys(SUPPORTED_REF_TYPES).some(key => { if ( + ids[key] !== undefined && SUPPORTED_REF_TYPES[key].isTypeFromReference( exports, - exportFunctionResponse + exportFunctionResponse, + ids[key] ) ) { supportedType = SUPPORTED_REF_TYPES[key]; diff --git a/lib/supported-ref-types.js b/lib/supported-ref-types.js index d732767..13b86e8 100644 --- a/lib/supported-ref-types.js +++ b/lib/supported-ref-types.js @@ -3,10 +3,10 @@ const SUPPORTED_REF_TYPES = { isTypeFromArgument: arg => { return typeof arg === "string"; }, - isTypeFromReference: (wasmExports, ref) => { - return wasmExports.__instanceof(ref, wasmExports.__asbind_String_ID); + isTypeFromReference: (wasmExports, ref, id) => { + return wasmExports.__instanceof(ref, id); }, - getRef: (wasmExports, arg) => { + getRef: (wasmExports, arg, id) => { return wasmExports.__retain(wasmExports.__allocString(arg)); }, getValueFromRef: (wasmExports, responseRef) => { @@ -17,13 +17,11 @@ const SUPPORTED_REF_TYPES = { isTypeFromArgument: arg => { return arg instanceof Int8Array; }, - isTypeFromReference: (wasmExports, ref) => { - return wasmExports.__instanceof(ref, wasmExports.__asbind_Int8Array_ID); + isTypeFromReference: (wasmExports, ref, id) => { + return wasmExports.__instanceof(ref, id); }, - getRef: (wasmExports, arg) => { - return wasmExports.__retain( - wasmExports.__allocArray(wasmExports.__asbind_Int8Array_ID, arg) - ); + getRef: (wasmExports, arg, id) => { + return wasmExports.__retain(wasmExports.__allocArray(id, arg)); }, getValueFromRef: (wasmExports, responseRef) => { return wasmExports.__getInt8Array(responseRef).slice(); @@ -33,13 +31,11 @@ const SUPPORTED_REF_TYPES = { isTypeFromArgument: arg => { return arg instanceof Uint8Array; }, - isTypeFromReference: (wasmExports, ref) => { - return wasmExports.__instanceof(ref, wasmExports.__asbind_Uint8Array_ID); + isTypeFromReference: (wasmExports, ref, id) => { + return wasmExports.__instanceof(ref, id); }, - getRef: (wasmExports, arg) => { - return wasmExports.__retain( - wasmExports.__allocArray(wasmExports.__asbind_Uint8Array_ID, arg) - ); + getRef: (wasmExports, arg, id) => { + return wasmExports.__retain(wasmExports.__allocArray(id, arg)); }, getValueFromRef: (wasmExports, responseRef) => { return wasmExports.__getUint8Array(responseRef).slice(); @@ -49,13 +45,11 @@ const SUPPORTED_REF_TYPES = { isTypeFromArgument: arg => { return arg instanceof Int16Array; }, - isTypeFromReference: (wasmExports, ref) => { - return wasmExports.__instanceof(ref, wasmExports.__asbind_Int16Array_ID); + isTypeFromReference: (wasmExports, ref, id) => { + return wasmExports.__instanceof(ref, id); }, - getRef: (wasmExports, arg) => { - return wasmExports.__retain( - wasmExports.__allocArray(wasmExports.__asbind_Int16Array_ID, arg) - ); + getRef: (wasmExports, arg, id) => { + return wasmExports.__retain(wasmExports.__allocArray(id, arg)); }, getValueFromRef: (wasmExports, responseRef) => { return wasmExports.__getInt16Array(responseRef).slice(); @@ -65,13 +59,11 @@ const SUPPORTED_REF_TYPES = { isTypeFromArgument: arg => { return arg instanceof Uint16Array; }, - isTypeFromReference: (wasmExports, ref) => { - return wasmExports.__instanceof(ref, wasmExports.__asbind_Uint16Array_ID); + isTypeFromReference: (wasmExports, ref, id) => { + return wasmExports.__instanceof(ref, id); }, - getRef: (wasmExports, arg) => { - return wasmExports.__retain( - wasmExports.__allocArray(wasmExports.__asbind_Uint16Array_ID, arg) - ); + getRef: (wasmExports, arg, id) => { + return wasmExports.__retain(wasmExports.__allocArray(id, arg)); }, getValueFromRef: (wasmExports, responseRef) => { return wasmExports.__getUint16Array(responseRef).slice(); @@ -81,13 +73,11 @@ const SUPPORTED_REF_TYPES = { isTypeFromArgument: arg => { return arg instanceof Int32Array; }, - isTypeFromReference: (wasmExports, ref) => { - return wasmExports.__instanceof(ref, wasmExports.__asbind_Int32Array_ID); + isTypeFromReference: (wasmExports, ref, id) => { + return wasmExports.__instanceof(ref, id); }, - getRef: (wasmExports, arg) => { - return wasmExports.__retain( - wasmExports.__allocArray(wasmExports.__asbind_Int32Array_ID, arg) - ); + getRef: (wasmExports, arg, id) => { + return wasmExports.__retain(wasmExports.__allocArray(id, arg)); }, getValueFromRef: (wasmExports, responseRef) => { return wasmExports.__getInt32Array(responseRef).slice(); @@ -97,13 +87,11 @@ const SUPPORTED_REF_TYPES = { isTypeFromArgument: arg => { return arg instanceof Uint32Array; }, - isTypeFromReference: (wasmExports, ref) => { - return wasmExports.__instanceof(ref, wasmExports.__asbind_Uint32Array_ID); + isTypeFromReference: (wasmExports, ref, id) => { + return wasmExports.__instanceof(ref, id); }, - getRef: (wasmExports, arg) => { - return wasmExports.__retain( - wasmExports.__allocArray(wasmExports.__asbind_Uint32Array_ID, arg) - ); + getRef: (wasmExports, arg, id) => { + return wasmExports.__retain(wasmExports.__allocArray(id, arg)); }, getValueFromRef: (wasmExports, responseRef) => { return wasmExports.__getUint32Array(responseRef).slice(); @@ -113,16 +101,11 @@ const SUPPORTED_REF_TYPES = { isTypeFromArgument: arg => { return arg instanceof Float32Array; }, - isTypeFromReference: (wasmExports, ref) => { - return wasmExports.__instanceof( - ref, - wasmExports.__asbind_Float32Array_ID - ); + isTypeFromReference: (wasmExports, ref, id) => { + return wasmExports.__instanceof(ref, id); }, - getRef: (wasmExports, arg) => { - return wasmExports.__retain( - wasmExports.__allocArray(wasmExports.__asbind_Float32Array_ID, arg) - ); + getRef: (wasmExports, arg, id) => { + return wasmExports.__retain(wasmExports.__allocArray(id, arg)); }, getValueFromRef: (wasmExports, responseRef) => { return wasmExports.__getFloat32Array(responseRef).slice(); @@ -132,16 +115,11 @@ const SUPPORTED_REF_TYPES = { isTypeFromArgument: arg => { return arg instanceof Float64Array; }, - isTypeFromReference: (wasmExports, ref) => { - return wasmExports.__instanceof( - ref, - wasmExports.__asbind_Float64Array_ID - ); + isTypeFromReference: (wasmExports, ref, id) => { + return wasmExports.__instanceof(ref, id); }, - getRef: (wasmExports, arg) => { - return wasmExports.__retain( - wasmExports.__allocArray(wasmExports.__asbind_Float64Array_ID, arg) - ); + getRef: (wasmExports, arg, id) => { + return wasmExports.__retain(wasmExports.__allocArray(id, arg)); }, getValueFromRef: (wasmExports, responseRef) => { return wasmExports.__getFloat64Array(responseRef).slice();