| // Generate some helper functions for manipulating (array (mut i16)) from JS | |
| let helperExports; | |
| { | |
| const builder = new WasmModuleBuilder(); | |
| const arrayIndex = builder.addArray(kWasmI16, true, kNoSuperType, true); | |
| builder | |
| .addFunction("createArrayMutI16", { | |
| params: [kWasmI32], | |
| results: [kWasmAnyRef] | |
| }) | |
| .addBody([ | |
| kExprLocalGet, | |
| ...wasmSignedLeb(0), | |
| ...GCInstr(kExprArrayNewDefault), | |
| ...wasmSignedLeb(arrayIndex) | |
| ]) | |
| .exportFunc(); | |
| builder | |
| .addFunction("arrayLength", { | |
| params: [kWasmArrayRef], | |
| results: [kWasmI32] | |
| }) | |
| .addBody([ | |
| kExprLocalGet, | |
| ...wasmSignedLeb(0), | |
| ...GCInstr(kExprArrayLen) | |
| ]) | |
| .exportFunc(); | |
| builder | |
| .addFunction("arraySet", { | |
| params: [wasmRefNullType(arrayIndex), kWasmI32, kWasmI32], | |
| results: [] | |
| }) | |
| .addBody([ | |
| kExprLocalGet, | |
| ...wasmSignedLeb(0), | |
| kExprLocalGet, | |
| ...wasmSignedLeb(1), | |
| kExprLocalGet, | |
| ...wasmSignedLeb(2), | |
| ...GCInstr(kExprArraySet), | |
| ...wasmSignedLeb(arrayIndex) | |
| ]) | |
| .exportFunc(); | |
| builder | |
| .addFunction("arrayGet", { | |
| params: [wasmRefNullType(arrayIndex), kWasmI32], | |
| results: [kWasmI32] | |
| }) | |
| .addBody([ | |
| kExprLocalGet, | |
| ...wasmSignedLeb(0), | |
| kExprLocalGet, | |
| ...wasmSignedLeb(1), | |
| ...GCInstr(kExprArrayGetU), | |
| ...wasmSignedLeb(arrayIndex) | |
| ]) | |
| .exportFunc(); | |
| let bytes = builder.toBuffer(); | |
| let module = new WebAssembly.Module(bytes); | |
| let instance = new WebAssembly.Instance(module); | |
| helperExports = instance.exports; | |
| } | |
| function throwIfNotString(a) { | |
| if (typeof a !== "string") { | |
| throw new WebAssembly.RuntimeError(); | |
| } | |
| } | |
| this.polyfillImports = { | |
| test: (string) => { | |
| if (string === null || | |
| typeof string !== "string") { | |
| return 0; | |
| } | |
| return 1; | |
| }, | |
| cast: (string) => { | |
| throwIfNotString(string); | |
| return string; | |
| }, | |
| fromCharCodeArray: (array, arrayStart, arrayCount) => { | |
| arrayStart >>>= 0; | |
| arrayCount >>>= 0; | |
| let length = helperExports.arrayLength(array); | |
| if (BigInt(arrayStart) + BigInt(arrayCount) > BigInt(length)) { | |
| throw new WebAssembly.RuntimeError(); | |
| } | |
| let result = ''; | |
| for (let i = arrayStart; i < arrayStart + arrayCount; i++) { | |
| result += String.fromCharCode(helperExports.arrayGet(array, i)); | |
| } | |
| return result; | |
| }, | |
| intoCharCodeArray: (string, arr, arrayStart) => { | |
| arrayStart >>>= 0; | |
| throwIfNotString(string); | |
| let arrLength = helperExports.arrayLength(arr); | |
| let stringLength = string.length; | |
| if (BigInt(arrayStart) + BigInt(stringLength) > BigInt(arrLength)) { | |
| throw new WebAssembly.RuntimeError(); | |
| } | |
| for (let i = 0; i < stringLength; i++) { | |
| helperExports.arraySet(arr, arrayStart + i, string[i].charCodeAt(0)); | |
| } | |
| return stringLength; | |
| }, | |
| fromCharCode: (charCode) => { | |
| charCode >>>= 0; | |
| return String.fromCharCode(charCode); | |
| }, | |
| fromCodePoint: (codePoint) => { | |
| codePoint >>>= 0; | |
| return String.fromCodePoint(codePoint); | |
| }, | |
| charCodeAt: (string, stringIndex) => { | |
| stringIndex >>>= 0; | |
| throwIfNotString(string); | |
| if (stringIndex >= string.length) | |
| throw new WebAssembly.RuntimeError(); | |
| return string.charCodeAt(stringIndex); | |
| }, | |
| codePointAt: (string, stringIndex) => { | |
| stringIndex >>>= 0; | |
| throwIfNotString(string); | |
| if (stringIndex >= string.length) | |
| throw new WebAssembly.RuntimeError(); | |
| return string.codePointAt(stringIndex); | |
| }, | |
| length: (string) => { | |
| throwIfNotString(string); | |
| return string.length; | |
| }, | |
| concat: (stringA, stringB) => { | |
| throwIfNotString(stringA); | |
| throwIfNotString(stringB); | |
| return stringA + stringB; | |
| }, | |
| substring: (string, startIndex, endIndex) => { | |
| startIndex >>>= 0; | |
| endIndex >>>= 0; | |
| throwIfNotString(string); | |
| if (startIndex > string.length, | |
| endIndex > string.length, | |
| endIndex < startIndex) { | |
| return ""; | |
| } | |
| return string.substring(startIndex, endIndex); | |
| }, | |
| equals: (stringA, stringB) => { | |
| if (stringA !== null) throwIfNotString(stringA); | |
| if (stringB !== null) throwIfNotString(stringB); | |
| return stringA === stringB; | |
| }, | |
| compare: (stringA, stringB) => { | |
| throwIfNotString(stringA); | |
| throwIfNotString(stringB); | |
| if (stringA < stringB) { | |
| return -1; | |
| } | |
| return stringA === stringB ? 0 : 1; | |
| }, | |
| }; |