Files
simple-rust-tests/__wasm/js-wasm/helloworld/js-wasm.js
2022-07-17 19:39:28 +08:00

245 lines
8.7 KiB
JavaScript

"use strict";
class Index {
constructor(index, generation) {
this.index = index;
this.generation = generation;
}
toNum() {
return Number((BigInt(this.generation) << BigInt(32)) | BigInt(this.index));
}
static fromNum(n) {
const i = Number(((BigInt(n) & BigInt(0xffffffff00000000)) >> BigInt(32)) &
BigInt(0xffffffff));
const g = n & 0xffffffff;
return new Index(g, i);
}
}
class GenerationalArena {
constructor() {
this.items = [];
this.generation = 0;
this.free_list_head = undefined;
this.length = 0;
}
insert(v) {
// lets use the first free entry if we have one
if (this.free_list_head !== undefined) {
let i = this.free_list_head;
this.free_list_head = this.items[i].nextFree;
this.items[i] = {
generation: this.generation,
value: v,
};
this.length += 1;
return new Index(i, this.generation);
}
this.items.push({
generation: this.generation,
value: v,
});
const idx = new Index(this.items.length - 1, this.generation);
this.length += 1;
return idx;
}
contains(idx) {
return this.get(idx) !== undefined;
}
get(i) {
let e = this.items[i.index];
if (e && e.generation === i.generation) {
return e.value;
}
return undefined;
}
remove(idx) {
if (idx.index >= this.items.length) {
return undefined;
}
let e = this.items[idx.index];
if (e.generation !== undefined && e.generation == idx.generation) {
this.generation += 1;
this.items[idx.index] = {
nextFree: this.free_list_head,
};
this.free_list_head = idx.index;
this.length -= 1;
return e.value;
}
return undefined;
}
*[Symbol.iterator]() {
for (let i = 0; i < this.items.length; i++) {
const x = this.items[i];
if (x.generation !== undefined) {
yield { index: new Index(i, x.generation), value: x.value };
}
}
}
indices() {
return {
items: this.items,
[Symbol.iterator]: function* iter() {
for (let i = 0; i < this.items.length; i++) {
const x = this.items[i];
if (x.generation !== undefined) {
yield new Index(i, x.generation);
}
}
},
};
}
values() {
return {
items: this.items,
[Symbol.iterator]: function* iter() {
for (let i = 0; i < this.items.length; i++) {
const x = this.items[i];
if (x.generation !== undefined) {
yield x.value;
}
}
},
};
}
}
const JsWasm = {
createEnvironment() {
const arena = new GenerationalArena();
arena.insert(undefined);
arena.insert(null);
arena.insert(self);
arena.insert(typeof document != "undefined" ? document : null);
arena.insert(typeof document != "undefined" ? document.body : null);
const context = {
functions: [
function () {
debugger;
return 0;
},
],
objects: arena,
utf8dec: new TextDecoder("utf-8"),
utf8enc: new TextEncoder(),
utf16dec: new TextDecoder("utf-16"),
toCallbackArg: function (arg) {
if (typeof arg === "object") {
return context.storeObject(arg);
}
return arg;
},
createCallback: function (cb) {
if (!this.module) {
throw new Error("module not set");
}
const fnHandleCallback = this.module.instance.exports.handle_callback;
return function () {
const arg = arguments;
fnHandleCallback(cb, context.toCallbackArg(arg[0]), context.toCallbackArg(arg[1]), context.toCallbackArg(arg[2]), context.toCallbackArg(arg[3]), context.toCallbackArg(arg[4]), context.toCallbackArg(arg[5]), context.toCallbackArg(arg[6]), context.toCallbackArg(arg[7]), context.toCallbackArg(arg[8]), context.toCallbackArg(arg[9]));
};
},
readUtf8FromMemory: function (start, len) {
const text = this.utf8dec.decode(this.getMemory().subarray(start, start + len));
return text;
},
createAllocation: function (size) {
if (!this.module) {
throw new Error("module not set");
}
const allocationId = this.module.instance.exports.create_allocation(size);
const allocationPtr = this.module.instance.exports.allocation_ptr(allocationId);
return [allocationId, allocationPtr];
},
writeUtf8ToMemory: function (str) {
const bytes = this.utf8enc.encode(str);
const len = bytes.length;
const [id, start] = this.createAllocation(len);
this.getMemory().set(bytes, start);
return id;
},
readUtf16FromMemory: function (start, len) {
const text = this.utf16dec.decode(this.getMemory().subarray(start, start + len));
return text;
},
readUint8ArrayFromMemory(start) {
if (!this.module) {
throw new Error("module not set");
}
const data32 = new Uint32Array(this.module.instance.exports.memory.buffer);
const ptr = data32[start / 4];
const length = data32[ptr / 4];
let b = this.getMemory().slice(ptr + 4, ptr + 4 + length);
return new Uint8Array(b);
},
storeObject: function (obj) {
const index = this.objects.insert(obj);
return index.toNum();
},
getObject: function (handle) {
return this.objects.get(Index.fromNum(handle));
},
releaseObject: function (handle) {
this.objects.remove(Index.fromNum(handle));
},
getMemory: function () {
if (!this.module) {
throw new Error("module not set");
}
return new Uint8Array(this.module.instance.exports.memory.buffer);
},
};
return [{
abort() {
throw new Error("WebAssembly module aborted");
},
js_release(obj) {
context.releaseObject(obj);
},
js_register_function(start, len, utfByteLen) {
let functionBody;
if (utfByteLen === 16) {
functionBody = context.readUtf16FromMemory(start, len);
}
else {
functionBody = context.readUtf8FromMemory(start, len);
}
let id = context.functions.length;
context.functions.push(Function(`"use strict";return(${functionBody})`)());
return id;
},
js_invoke_function(funcHandle, a, b, c, d, e, f, g, h, i, j) {
return context.functions[funcHandle].call(context, a, b, c, d, e, f, g, h, i, j);
},
}, context];
},
async loadAndRunWasm(wasmURL) {
const [env, context] = JsWasm.createEnvironment();
const response = await fetch(wasmURL);
const bytes = await response.arrayBuffer();
const module = await WebAssembly.instantiate(bytes, {
env,
});
context.module = module;
module.instance.exports.main();
},
};
document.addEventListener("DOMContentLoaded", function () {
const wasmScripts = document.querySelectorAll("script[type='application/wasm']");
for (let i = 0; i < wasmScripts.length; i++) {
const src = wasmScripts[i].src;
if (src) {
JsWasm.loadAndRunWasm(src);
}
else {
console.error("Script tag must have 'src' property.");
}
}
});
if (window.WasmScriptComponents) {
window.WasmScriptComponents["js-wasm"] = function (e) {
return {
...e,
...JsWasm.createEnvironment(),
};
};
}