rc-js-util
Version:
A collection of TS and C++ utilities to help writing performant and correct applications, achieved through strict typing and (removable) invariant checking.
134 lines • 5.25 kB
JavaScript
import { __awaiter } from "tslib";
import { shimWebAssemblyMemory } from "../util/shim-web-assembly-memory.js";
import { BroadcastChannel } from "../../eventing/broadcast-channel.js";
import { _Debug } from "../../debug/_debug.js";
import { DebugWeakBroadcastChannel } from "../../debug/debug-weak-broadcast-event.js";
import { DebugSharedObjectLifeCycleChecker } from "../../debug/debug-shared-object-life-cycle-checker.js";
import { DebugWeakStore } from "../../debug/debug-weak-store.js";
import { StableIdStore } from "../../runtime/rtti-interop.js";
/**
* @public
* Factory for creating wrapped emscripten module.
*/
export function getEmscriptenWrapper(memory_1, emscriptenModuleFactory_1, lifecycleStrategy_1, options_1) {
return __awaiter(this, arguments, void 0, function* (memory, emscriptenModuleFactory, lifecycleStrategy, options, extension = {}) {
let debugLabel = undefined;
try {
if (_BUILD.DEBUG) {
debugLabel = _Debug.label;
_Debug.label = "EmscriptenWrapper";
}
const memoryListener = _BUILD.DEBUG
? new DebugWeakBroadcastChannel("onMemoryResize")
: new BroadcastChannel("onMemoryResize");
const debug = new EmscriptenDebug();
const binder = new EmscriptenBinder();
if (_BUILD.DEBUG) {
const debugInstance = extension;
debugInstance.JSU_DEBUG_UTIL = debug;
}
const instance = yield emscriptenModuleFactory(Object.assign({ wasmMemory: memory, INITIAL_MEMORY: memory.buffer.byteLength, JSU_BINDER: binder }, extension));
const wrapper = new EmscriptenWrapper(memoryListener, instance, memory, debug, binder, lifecycleStrategy, options);
lifecycleStrategy.setWrapper(wrapper);
// this depends on the lifecycle strategy having being initialized...
wrapper.interopIds.initialize();
initializeSubmodules(instance);
return wrapper;
}
finally {
if (_BUILD.DEBUG) {
_Debug.label = debugLabel;
}
}
});
}
/**
* @public
*/
export class EmscriptenWrapperOptions {
constructor(initializeCallbacks) {
this.initializeCallbacks = initializeCallbacks;
}
extend(options) {
return new EmscriptenWrapperOptions(this.initializeCallbacks.concat(options.initializeCallbacks));
}
}
class EmscriptenWrapper {
constructor(memoryResize, instance, memory, debugUtils, binder, lifecycleStrategy, options, rootNode = lifecycleStrategy.createRootNode()) {
this.memoryResize = memoryResize;
this.instance = instance;
this.memory = memory;
this.debugUtils = debugUtils;
this.binder = binder;
this.lifecycleStrategy = lifecycleStrategy;
this.rootNode = rootNode;
this.interopIds = new StableIdStore(this);
const state = this.state = new EWState(new DataView(memory.buffer));
// in debug builds there are retainers on the wasm memory from libraries, sidestep by passing sub-object
// don't reference `this` here...
shimWebAssemblyMemory(memory, (buffer, previous, delta) => {
_BUILD.DEBUG && _Debug.verboseLog(["WASM", "MEMORY"], `WebAssembly memory grew from ${previous} to ${previous + delta} pages.`);
state.dataView = new DataView(memory.buffer);
memoryResize.emit(buffer, previous, delta);
});
const callbacks = options.initializeCallbacks;
for (let i = 0, iEnd = callbacks.length; i < iEnd; i++) {
callbacks[i](this);
}
}
destroyLinked() {
this.rootNode.getLinked().unlinkAll();
}
getDataView() {
return this.state.dataView;
}
}
class EmscriptenDebug {
constructor() {
this.onAllocate = new DebugWeakBroadcastChannel("debugOnAllocate");
this.protectedViews = new DebugWeakStore();
this.sharedObjectLifeCycleChecks = new DebugSharedObjectLifeCycleChecker();
this.uniquePointers = new Set();
}
error(message) {
_Debug.error(message);
}
verboseLog(tags, message) {
_Debug.verboseLog(tags, message);
}
}
class EmscriptenBinder {
constructor() {
this.bindingObjects = new Map();
this.counter = 0;
}
pushBinder(interopObject) {
const index = this.counter;
++this.counter;
this.bindingObjects.set(index, interopObject);
return index;
}
getBinder(index) {
return this.bindingObjects.get(index);
}
removeBinder(index) {
return this.bindingObjects.delete(index);
}
}
class EWState {
constructor(dataView) {
this.dataView = dataView;
}
}
function initializeSubmodules(instance) {
const keys = Object.keys(instance);
for (let i = 0, iEnd = keys.length; i < iEnd; i++) {
const key = keys[i];
if (key.startsWith("_jsuInitialize")) {
const fn = instance[key];
_BUILD.DEBUG && _Debug.assert(fn.length === 0, "initialization function must be parameterless");
fn();
}
}
}
//# sourceMappingURL=get-emscripten-wrapper.js.map