Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Derive ids from RTTI #21

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions lib/asbind-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {};
}
Expand Down Expand Up @@ -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 => {
Expand Down
22 changes: 11 additions & 11 deletions lib/assembly/as-bind.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// Neccessary bootstrapping for asbind

// Strings
export const __asbind_String_ID = idof<String>();
// export const __asbind_String_ID = idof<String>();

// ArrayBuffers
// TODO: Maybe support these?
export const __asbind_ArrayBuffer_ID = idof<ArrayBuffer>();
export const __asbind_ArrayBufferView_ID = idof<ArrayBufferView>();
// export const __asbind_ArrayBuffer_ID = idof<ArrayBuffer>();
// export const __asbind_ArrayBufferView_ID = idof<ArrayBufferView>();

// Typed Arrays
export const __asbind_Int8Array_ID = idof<Int8Array>();
export const __asbind_Uint8Array_ID = idof<Uint8Array>();
export const __asbind_Int16Array_ID = idof<Int16Array>();
export const __asbind_Uint16Array_ID = idof<Uint16Array>();
export const __asbind_Int32Array_ID = idof<Int32Array>();
export const __asbind_Uint32Array_ID = idof<Uint32Array>();
export const __asbind_Float32Array_ID = idof<Float32Array>();
export const __asbind_Float64Array_ID = idof<Float64Array>();
// export const __asbind_Int8Array_ID = idof<Int8Array>();
// export const __asbind_Uint8Array_ID = idof<Uint8Array>();
// export const __asbind_Int16Array_ID = idof<Int16Array>();
// export const __asbind_Uint16Array_ID = idof<Uint16Array>();
// export const __asbind_Int32Array_ID = idof<Int32Array>();
// export const __asbind_Uint32Array_ID = idof<Uint32Array>();
// export const __asbind_Float32Array_ID = idof<Float32Array>();
// export const __asbind_Float64Array_ID = idof<Float64Array>();
24 changes: 19 additions & 5 deletions lib/bind-function.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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] = {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -138,15 +142,17 @@ 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 (
functionThis.shouldCacheTypes &&
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 => {
Expand All @@ -158,6 +164,7 @@ export function bindExportFunction(asbindInstance, exportFunctionKey) {
key
};
}
id = ids[key];
return true;
}

Expand All @@ -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);
});

Expand Down Expand Up @@ -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];
Expand Down
92 changes: 35 additions & 57 deletions lib/supported-ref-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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();
Expand Down