@dacely/toilscript-loader 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js ADDED
@@ -0,0 +1,453 @@
1
+ // Runtime header offsets
2
+ const ID_OFFSET = -8;
3
+ const SIZE_OFFSET = -4;
4
+
5
+ // Runtime ids
6
+ // const OBJECT_ID = 0;
7
+ const ARRAYBUFFER_ID = 1;
8
+ const STRING_ID = 2;
9
+
10
+ // Runtime type information
11
+ const ARRAYBUFFERVIEW = 1 << 0;
12
+ const ARRAY = 1 << 1;
13
+ const STATICARRAY = 1 << 2;
14
+ // const SET = 1 << 3;
15
+ // const MAP = 1 << 4;
16
+ const VAL_ALIGN_OFFSET = 6;
17
+ // const VAL_ALIGN = 1 << VAL_ALIGN_OFFSET;
18
+ const VAL_SIGNED = 1 << 11;
19
+ const VAL_FLOAT = 1 << 12;
20
+ // const VAL_NULLABLE = 1 << 13;
21
+ const VAL_MANAGED = 1 << 14;
22
+ // const KEY_ALIGN_OFFSET = 15;
23
+ // const KEY_ALIGN = 1 << KEY_ALIGN_OFFSET;
24
+ // const KEY_SIGNED = 1 << 20;
25
+ // const KEY_FLOAT = 1 << 21;
26
+ // const KEY_NULLABLE = 1 << 22;
27
+ // const KEY_MANAGED = 1 << 23;
28
+
29
+ // Array(BufferView) layout
30
+ const ARRAYBUFFERVIEW_BUFFER_OFFSET = 0;
31
+ const ARRAYBUFFERVIEW_DATASTART_OFFSET = 4;
32
+ const ARRAYBUFFERVIEW_BYTELENGTH_OFFSET = 8;
33
+ const ARRAYBUFFERVIEW_SIZE = 12;
34
+ const ARRAY_LENGTH_OFFSET = 12;
35
+ const ARRAY_SIZE = 16;
36
+
37
+ const E_NO_EXPORT_TABLE = "Operation requires compiling with --exportTable";
38
+ const E_NO_EXPORT_RUNTIME = "Operation requires compiling with --exportRuntime";
39
+ const F_NO_EXPORT_RUNTIME = () => { throw Error(E_NO_EXPORT_RUNTIME); };
40
+
41
+ const BIGINT = typeof BigUint64Array !== "undefined";
42
+ const THIS = Symbol();
43
+
44
+ const STRING_SMALLSIZE = 192; // break-even point in V8
45
+ const STRING_CHUNKSIZE = 1024; // mitigate stack overflow
46
+ const utf16 = new TextDecoder("utf-16le", { fatal: true }); // != wtf16
47
+
48
+ /** polyfill for Object.hasOwn */
49
+ Object.hasOwn = Object.hasOwn || function(obj, prop) {
50
+ return Object.prototype.hasOwnProperty.call(obj, prop);
51
+ };
52
+
53
+ /** Gets a string from memory. */
54
+ function getStringImpl(buffer, ptr) {
55
+ let len = new Uint32Array(buffer)[ptr + SIZE_OFFSET >>> 2] >>> 1;
56
+ const wtf16 = new Uint16Array(buffer, ptr, len);
57
+ if (len <= STRING_SMALLSIZE) return String.fromCharCode(...wtf16);
58
+ try {
59
+ return utf16.decode(wtf16);
60
+ } catch {
61
+ let str = "", off = 0;
62
+ while (len - off > STRING_CHUNKSIZE) {
63
+ str += String.fromCharCode(...wtf16.subarray(off, off += STRING_CHUNKSIZE));
64
+ }
65
+ return str + String.fromCharCode(...wtf16.subarray(off));
66
+ }
67
+ }
68
+
69
+ /** Prepares the base module prior to instantiation. */
70
+ function preInstantiate(imports) {
71
+ const extendedExports = {};
72
+
73
+ function getString(memory, ptr) {
74
+ if (!memory) return "<yet unknown>";
75
+ return getStringImpl(memory.buffer, ptr);
76
+ }
77
+
78
+ // add common imports used by stdlib for convenience
79
+ const env = (imports.env = imports.env || {});
80
+ env.abort = env.abort || function abort(msg, file, line, colm) {
81
+ const memory = extendedExports.memory || env.memory; // prefer exported, otherwise try imported
82
+ throw Error(`abort: ${getString(memory, msg)} at ${getString(memory, file)}:${line}:${colm}`);
83
+ };
84
+ env.trace = env.trace || function trace(msg, n, ...args) {
85
+ const memory = extendedExports.memory || env.memory;
86
+ console.log(`trace: ${getString(memory, msg)}${n ? " " : ""}${args.slice(0, n).join(", ")}`);
87
+ };
88
+ env.seed = env.seed || Date.now;
89
+ imports.Math = imports.Math || Math;
90
+ imports.Date = imports.Date || Date;
91
+
92
+ return extendedExports;
93
+ }
94
+
95
+ /** Prepares the final module once instantiation is complete. */
96
+ function postInstantiate(extendedExports, instance) {
97
+ const exports = instance.exports;
98
+ const memory = exports.memory;
99
+ const table = exports.table;
100
+ const __new = exports.__new || F_NO_EXPORT_RUNTIME;
101
+ const __pin = exports.__pin || F_NO_EXPORT_RUNTIME;
102
+ const __unpin = exports.__unpin || F_NO_EXPORT_RUNTIME;
103
+ const __collect = exports.__collect || F_NO_EXPORT_RUNTIME;
104
+ const __rtti_base = exports.__rtti_base;
105
+ const getTypeinfoCount = __rtti_base ? arr => arr[__rtti_base >>> 2] : F_NO_EXPORT_RUNTIME;
106
+
107
+ extendedExports.__new = __new;
108
+ extendedExports.__pin = __pin;
109
+ extendedExports.__unpin = __unpin;
110
+ extendedExports.__collect = __collect;
111
+
112
+ /** Gets the runtime type info for the given id. */
113
+ function getTypeinfo(id) {
114
+ const U32 = new Uint32Array(memory.buffer);
115
+ if ((id >>>= 0) >= getTypeinfoCount(U32)) throw Error(`invalid id: ${id}`);
116
+ return U32[(__rtti_base + 4 >>> 2) + id];
117
+ }
118
+
119
+ /** Gets and validates runtime type info for the given id for array like objects */
120
+ function getArrayInfo(id) {
121
+ const info = getTypeinfo(id);
122
+ if (!(info & (ARRAYBUFFERVIEW | ARRAY | STATICARRAY))) throw Error(`not an array: ${id}, flags=${info}`);
123
+ return info;
124
+ }
125
+
126
+ /** Gets the runtime alignment of a collection's values. */
127
+ function getValueAlign(info) {
128
+ return 31 - Math.clz32((info >>> VAL_ALIGN_OFFSET) & 31); // -1 if none
129
+ }
130
+
131
+ /** Gets the runtime alignment of a collection's keys. */
132
+ // function getKeyAlign(info) {
133
+ // return 31 - Math.clz32((info >>> KEY_ALIGN_OFFSET) & 31); // -1 if none
134
+ // }
135
+
136
+ /** Allocates a new string in the module's memory and returns its pointer. */
137
+ function __newString(str) {
138
+ if (str == null) return 0;
139
+ const length = str.length;
140
+ const ptr = __new(length << 1, STRING_ID);
141
+ const U16 = new Uint16Array(memory.buffer);
142
+ for (let i = 0, p = ptr >>> 1; i < length; ++i) U16[p + i] = str.charCodeAt(i);
143
+ return ptr;
144
+ }
145
+
146
+ extendedExports.__newString = __newString;
147
+
148
+ /** Allocates a new ArrayBuffer in the module's memory and returns its pointer. */
149
+ function __newArrayBuffer(buf) {
150
+ if (buf == null) return 0;
151
+ const bufview = new Uint8Array(buf);
152
+ const ptr = __new(bufview.length, ARRAYBUFFER_ID);
153
+ const U8 = new Uint8Array(memory.buffer);
154
+ U8.set(bufview, ptr);
155
+ return ptr;
156
+ }
157
+
158
+ extendedExports.__newArrayBuffer = __newArrayBuffer;
159
+
160
+ /** Reads a string from the module's memory by its pointer. */
161
+ function __getString(ptr) {
162
+ if (!ptr) return null;
163
+ const buffer = memory.buffer;
164
+ const id = new Uint32Array(buffer)[ptr + ID_OFFSET >>> 2];
165
+ if (id !== STRING_ID) throw Error(`not a string: ${ptr}`);
166
+ return getStringImpl(buffer, ptr);
167
+ }
168
+
169
+ extendedExports.__getString = __getString;
170
+
171
+ /** Gets the view matching the specified alignment, signedness and floatness. */
172
+ function getView(alignLog2, signed, float) {
173
+ const buffer = memory.buffer;
174
+ if (float) {
175
+ switch (alignLog2) {
176
+ case 2: return new Float32Array(buffer);
177
+ case 3: return new Float64Array(buffer);
178
+ }
179
+ } else {
180
+ switch (alignLog2) {
181
+ case 0: return new (signed ? Int8Array : Uint8Array)(buffer);
182
+ case 1: return new (signed ? Int16Array : Uint16Array)(buffer);
183
+ case 2: return new (signed ? Int32Array : Uint32Array)(buffer);
184
+ case 3: return new (signed ? BigInt64Array : BigUint64Array)(buffer);
185
+ }
186
+ }
187
+ throw Error(`unsupported align: ${alignLog2}`);
188
+ }
189
+
190
+ /** Allocates a new array in the module's memory and returns its pointer. */
191
+ function __newArray(id, valuesOrCapacity = 0) {
192
+ const input = valuesOrCapacity;
193
+ const info = getArrayInfo(id);
194
+ const align = getValueAlign(info);
195
+ const isArrayLike = typeof input !== "number";
196
+ const length = isArrayLike ? input.length : input;
197
+ const buf = __new(length << align, info & STATICARRAY ? id : ARRAYBUFFER_ID);
198
+ let result;
199
+ if (info & STATICARRAY) {
200
+ result = buf;
201
+ } else {
202
+ __pin(buf);
203
+ const arr = __new(info & ARRAY ? ARRAY_SIZE : ARRAYBUFFERVIEW_SIZE, id);
204
+ __unpin(buf);
205
+ const U32 = new Uint32Array(memory.buffer);
206
+ U32[arr + ARRAYBUFFERVIEW_BUFFER_OFFSET >>> 2] = buf;
207
+ U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2] = buf;
208
+ U32[arr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] = length << align;
209
+ if (info & ARRAY) U32[arr + ARRAY_LENGTH_OFFSET >>> 2] = length;
210
+ result = arr;
211
+ }
212
+ if (isArrayLike) {
213
+ const view = getView(align, info & VAL_SIGNED, info & VAL_FLOAT);
214
+ const start = buf >>> align;
215
+ if (info & VAL_MANAGED) {
216
+ for (let i = 0; i < length; ++i) {
217
+ view[start + i] = input[i];
218
+ }
219
+ } else {
220
+ view.set(input, start);
221
+ }
222
+ }
223
+ return result;
224
+ }
225
+
226
+ extendedExports.__newArray = __newArray;
227
+
228
+ /** Gets a live view on an array's values in the module's memory. Infers the array type from RTTI. */
229
+ function __getArrayView(arr) {
230
+ const U32 = new Uint32Array(memory.buffer);
231
+ const id = U32[arr + ID_OFFSET >>> 2];
232
+ const info = getArrayInfo(id);
233
+ const align = getValueAlign(info);
234
+ let buf = info & STATICARRAY
235
+ ? arr
236
+ : U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2];
237
+ const length = info & ARRAY
238
+ ? U32[arr + ARRAY_LENGTH_OFFSET >>> 2]
239
+ : U32[buf + SIZE_OFFSET >>> 2] >>> align;
240
+ return getView(align, info & VAL_SIGNED, info & VAL_FLOAT).subarray(buf >>>= align, buf + length);
241
+ }
242
+
243
+ extendedExports.__getArrayView = __getArrayView;
244
+
245
+ /** Copies an array's values from the module's memory. Infers the array type from RTTI. */
246
+ function __getArray(arr) {
247
+ const input = __getArrayView(arr);
248
+ const len = input.length;
249
+ const out = new Array(len);
250
+ for (let i = 0; i < len; i++) out[i] = input[i];
251
+ return out;
252
+ }
253
+
254
+ extendedExports.__getArray = __getArray;
255
+
256
+ /** Copies an ArrayBuffer's value from the module's memory. */
257
+ function __getArrayBuffer(ptr) {
258
+ const buffer = memory.buffer;
259
+ const length = new Uint32Array(buffer)[ptr + SIZE_OFFSET >>> 2];
260
+ return buffer.slice(ptr, ptr + length);
261
+ }
262
+
263
+ extendedExports.__getArrayBuffer = __getArrayBuffer;
264
+
265
+ /** Gets a function from poiner which contain table's index. */
266
+ function __getFunction(ptr) {
267
+ if (!table) throw Error(E_NO_EXPORT_TABLE);
268
+ const index = new Uint32Array(memory.buffer)[ptr >>> 2];
269
+ return table.get(index);
270
+ }
271
+
272
+ extendedExports.__getFunction = __getFunction;
273
+
274
+ /** Copies a typed array's values from the module's memory. */
275
+ function getTypedArray(Type, alignLog2, ptr) {
276
+ return new Type(getTypedArrayView(Type, alignLog2, ptr));
277
+ }
278
+
279
+ /** Gets a live view on a typed array's values in the module's memory. */
280
+ function getTypedArrayView(Type, alignLog2, ptr) {
281
+ const buffer = memory.buffer;
282
+ const U32 = new Uint32Array(buffer);
283
+ return new Type(
284
+ buffer,
285
+ U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2],
286
+ U32[ptr + ARRAYBUFFERVIEW_BYTELENGTH_OFFSET >>> 2] >>> alignLog2
287
+ );
288
+ }
289
+
290
+ /** Attach a set of get TypedArray and View functions to the exports. */
291
+ function attachTypedArrayFunctions(ctor, name, align) {
292
+ extendedExports[`__get${name}`] = getTypedArray.bind(null, ctor, align);
293
+ extendedExports[`__get${name}View`] = getTypedArrayView.bind(null, ctor, align);
294
+ }
295
+
296
+ [
297
+ Int8Array,
298
+ Uint8Array,
299
+ Uint8ClampedArray,
300
+ Int16Array,
301
+ Uint16Array,
302
+ Int32Array,
303
+ Uint32Array,
304
+ Float32Array,
305
+ Float64Array
306
+ ].forEach(ctor => {
307
+ attachTypedArrayFunctions(ctor, ctor.name, 31 - Math.clz32(ctor.BYTES_PER_ELEMENT));
308
+ });
309
+
310
+ if (BIGINT) {
311
+ [BigUint64Array, BigInt64Array].forEach(ctor => {
312
+ attachTypedArrayFunctions(ctor, ctor.name.slice(3), 3);
313
+ });
314
+ }
315
+
316
+ // Pull basic exports to extendedExports so code in preInstantiate can use them
317
+ extendedExports.memory = extendedExports.memory || memory;
318
+ extendedExports.table = extendedExports.table || table;
319
+
320
+ // Demangle exports and provide the usual utility on the prototype
321
+ return demangle(exports, extendedExports);
322
+ }
323
+
324
+ function isResponse(src) {
325
+ return typeof Response !== "undefined" && src instanceof Response;
326
+ }
327
+
328
+ function isModule(src) {
329
+ return src instanceof WebAssembly.Module;
330
+ }
331
+
332
+ /** Asynchronously instantiates an AssemblyScript module from anything that can be instantiated. */
333
+ export async function instantiate(source, imports = {}) {
334
+ if (isResponse(source = await source)) return instantiateStreaming(source, imports);
335
+ const module = isModule(source) ? source : await WebAssembly.compile(source);
336
+ const extended = preInstantiate(imports);
337
+ const instance = await WebAssembly.instantiate(module, imports);
338
+ const exports = postInstantiate(extended, instance);
339
+ return { module, instance, exports };
340
+ }
341
+
342
+ /** Synchronously instantiates an AssemblyScript module from a WebAssembly.Module or binary buffer. */
343
+ export function instantiateSync(source, imports = {}) {
344
+ const module = isModule(source) ? source : new WebAssembly.Module(source);
345
+ const extended = preInstantiate(imports);
346
+ const instance = new WebAssembly.Instance(module, imports);
347
+ const exports = postInstantiate(extended, instance);
348
+ return { module, instance, exports };
349
+ }
350
+
351
+ /** Asynchronously instantiates an AssemblyScript module from a response, i.e. as obtained by `fetch`. */
352
+ export async function instantiateStreaming(source, imports = {}) {
353
+ if (!WebAssembly.instantiateStreaming) {
354
+ return instantiate(
355
+ isResponse(source = await source)
356
+ ? source.arrayBuffer()
357
+ : source,
358
+ imports
359
+ );
360
+ }
361
+ const extended = preInstantiate(imports);
362
+ const result = await WebAssembly.instantiateStreaming(source, imports);
363
+ const exports = postInstantiate(extended, result.instance);
364
+ return { ...result, exports };
365
+ }
366
+
367
+ /** Demangles an AssemblyScript module's exports to a friendly object structure. */
368
+ export function demangle(exports, extendedExports = {}) {
369
+ const setArgumentsLength = exports["__argumentsLength"]
370
+ ? length => { exports["__argumentsLength"].value = length; }
371
+ : exports["__setArgumentsLength"] || exports["__setargc"] || (() => { /* nop */ });
372
+ for (let internalName of Object.keys(exports)) {
373
+ const elem = exports[internalName];
374
+ let parts = internalName.split(".");
375
+ let curr = extendedExports;
376
+ while (parts.length > 1) {
377
+ let part = parts.shift();
378
+ if (!Object.hasOwn(curr, part)) curr[part] = {};
379
+ curr = curr[part];
380
+ }
381
+ let name = parts[0];
382
+ let hash = name.indexOf("#");
383
+ if (hash >= 0) {
384
+ const className = name.substring(0, hash);
385
+ const classElem = curr[className];
386
+ if (typeof classElem === "undefined" || !classElem.prototype) {
387
+ const ctor = function(...args) {
388
+ return ctor.wrap(ctor.prototype.constructor(0, ...args));
389
+ };
390
+ ctor.prototype = {
391
+ valueOf() { return this[THIS]; }
392
+ };
393
+ ctor.wrap = function(thisValue) {
394
+ return Object.create(ctor.prototype, { [THIS]: { value: thisValue, writable: false } });
395
+ };
396
+ if (classElem) Object.getOwnPropertyNames(classElem).forEach(name =>
397
+ Object.defineProperty(ctor, name, Object.getOwnPropertyDescriptor(classElem, name))
398
+ );
399
+ curr[className] = ctor;
400
+ }
401
+ name = name.substring(hash + 1);
402
+ curr = curr[className].prototype;
403
+ if (/^(get|set):/.test(name)) {
404
+ if (!Object.hasOwn(curr, name = name.substring(4))) {
405
+ let getter = exports[internalName.replace("set:", "get:")];
406
+ let setter = exports[internalName.replace("get:", "set:")];
407
+ Object.defineProperty(curr, name, {
408
+ get() { return getter(this[THIS]); },
409
+ set(value) { setter(this[THIS], value); },
410
+ enumerable: true
411
+ });
412
+ }
413
+ } else {
414
+ if (name === 'constructor') {
415
+ (curr[name] = function(...args) {
416
+ setArgumentsLength(args.length);
417
+ return elem(...args);
418
+ }).original = elem;
419
+ } else { // instance method
420
+ (curr[name] = function(...args) { // !
421
+ setArgumentsLength(args.length);
422
+ return elem(this[THIS], ...args);
423
+ }).original = elem;
424
+ }
425
+ }
426
+ } else {
427
+ if (/^(get|set):/.test(name)) {
428
+ if (!Object.hasOwn(curr, name = name.substring(4))) {
429
+ Object.defineProperty(curr, name, {
430
+ get: exports[internalName.replace("set:", "get:")],
431
+ set: exports[internalName.replace("get:", "set:")],
432
+ enumerable: true
433
+ });
434
+ }
435
+ } else if (typeof elem === "function" && elem !== setArgumentsLength) {
436
+ (curr[name] = (...args) => {
437
+ setArgumentsLength(args.length);
438
+ return elem(...args);
439
+ }).original = elem;
440
+ } else {
441
+ curr[name] = elem;
442
+ }
443
+ }
444
+ }
445
+ return extendedExports;
446
+ }
447
+
448
+ export default {
449
+ instantiate,
450
+ instantiateSync,
451
+ instantiateStreaming,
452
+ demangle
453
+ };
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@dacely/toilscript-loader",
3
+ "description": "A convenient loader for ToilScript modules.",
4
+ "keywords": [
5
+ "toilscript",
6
+ "loader",
7
+ "glue",
8
+ "interop",
9
+ "webassembly",
10
+ "wasm"
11
+ ],
12
+ "version": "0.0.0",
13
+ "author": "Daniel Wirtz <dcode+assemblyscript@dcode.io>",
14
+ "contributors": [
15
+ "MaxGraey <maxgraey@gmail.com>"
16
+ ],
17
+ "license": "Apache-2.0",
18
+ "homepage": "https://assemblyscript.org",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/AssemblyScript/assemblyscript.git",
22
+ "directory": "lib/loader"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/AssemblyScript/assemblyscript/issues"
26
+ },
27
+ "type": "module",
28
+ "main": "./umd/index.js",
29
+ "types": "index.d.ts",
30
+ "exports": {
31
+ "import": "./index.js",
32
+ "require": "./umd/index.js"
33
+ },
34
+ "scripts": {
35
+ "asbuild": "npm run asbuild:default && npm run asbuild:legacy",
36
+ "asbuild:default": "node ../../bin/asc tests/assembly/index.ts --outFile tests/build/default.wasm --exportRuntime --exportTable",
37
+ "asbuild:legacy": "node ../../bin/asc tests/assembly/index.ts --disable mutable-globals --outFile tests/build/legacy.wasm --exportRuntime --exportTable",
38
+ "build": "npx esm2umd loader index.js > umd/index.js",
39
+ "test": "node tests && node tests/umd"
40
+ },
41
+ "files": [
42
+ "index.d.ts",
43
+ "index.js",
44
+ "package.json",
45
+ "umd/index.d.ts",
46
+ "umd/index.js",
47
+ "umd/package.json",
48
+ "README.md"
49
+ ],
50
+ "devDependencies": {
51
+ "esm2umd": "^0.3.1"
52
+ }
53
+ }
package/umd/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "../index";