{{{
const EMVAL_RESERVED_HANDLES = 5;
const EMVAL_LAST_RESERVED_HANDLE = EMVAL_RESERVED_HANDLES * 2 - 1;
}}}
var LibraryEmVal = {
$emval_freelist: [],
$emval_handles: [
0, 1,
undefined, 1,
null, 1,
true, 1,
false, 1,
],
#if ASSERTIONS
$emval_handles__postset: 'assert(emval_handles.length === {{{ EMVAL_RESERVED_HANDLES }}} * 2)',
#endif
$emval_symbols: {},
$count_emval_handles__deps: ['$emval_freelist', '$emval_handles'],
$count_emval_handles: () => {
return emval_handles.length / 2 - {{{ EMVAL_RESERVED_HANDLES }}} - emval_freelist.length;
},
_emval_register_symbol__deps: ['$emval_symbols', '$AsciiToString'],
_emval_register_symbol: (address) => {
emval_symbols[address] = AsciiToString(address);
},
$getStringOrSymbol__deps: ['$emval_symbols', '$AsciiToString'],
$getStringOrSymbol: (address) => {
var symbol = emval_symbols[address];
if (symbol === undefined) {
return AsciiToString(address);
}
return symbol;
},
$Emval__deps: ['$emval_freelist', '$emval_handles', '$throwBindingError'],
$Emval: {
toValue: (handle) => {
if (!handle) {
throwBindingError(`Cannot use deleted val. handle = ${handle}`);
}
#if ASSERTIONS
assert(handle === 2 || emval_handles[handle] !== undefined && handle % 2 === 0, `invalid handle: ${handle}`);
#endif
return emval_handles[handle];
},
toHandle: (value) => {
switch (value) {
case undefined: return 2;
case null: return 4;
case true: return 6;
case false: return 8;
default:{
const handle = emval_freelist.pop() || emval_handles.length;
emval_handles[handle] = value;
emval_handles[handle + 1] = 1;
return handle;
}
}
}
},
_emval_incref__deps: ['$emval_handles'],
_emval_incref: (handle) => {
if (handle > {{{ EMVAL_LAST_RESERVED_HANDLE }}}) {
emval_handles[handle + 1] += 1;
}
},
_emval_decref__deps: ['$emval_freelist', '$emval_handles'],
_emval_decref: (handle) => {
if (handle > {{{ EMVAL_LAST_RESERVED_HANDLE }}} && 0 === --emval_handles[handle + 1]) {
#if ASSERTIONS
assert(emval_handles[handle] !== undefined, `Decref for unallocated handle.`);
#endif
emval_handles[handle] = undefined;
emval_freelist.push(handle);
}
},
_emval_run_destructors__deps: ['_emval_decref', '$Emval', '$runDestructors'],
_emval_run_destructors: (handle) => {
var destructors = Emval.toValue(handle);
runDestructors(destructors);
__emval_decref(handle);
},
_emval_new_array__deps: ['$Emval'],
_emval_new_array: () => Emval.toHandle([]),
_emval_new_array_from_memory_view__deps: ['$Emval'],
_emval_new_array_from_memory_view: (view) => {
view = Emval.toValue(view);
var a = new Array(view.length);
for (var i = 0; i < view.length; i++) a[i] = view[i];
return Emval.toHandle(a);
},
_emval_new_object__deps: ['$Emval'],
_emval_new_object: () => Emval.toHandle({}),
_emval_new_cstring__deps: ['$getStringOrSymbol', '$Emval'],
_emval_new_cstring: (v) => Emval.toHandle(getStringOrSymbol(v)),
_emval_new_u8string__deps: ['$Emval'],
_emval_new_u8string: (v) => Emval.toHandle(UTF8ToString(v)),
_emval_new_u16string__deps: ['$Emval'],
_emval_new_u16string: (v) => Emval.toHandle(UTF16ToString(v)),
_emval_get_global__deps: ['$Emval', '$getStringOrSymbol', '$emGlobalThis'],
_emval_get_global: (name) => {
if (!name) {
return Emval.toHandle(emGlobalThis);
}
name = getStringOrSymbol(name);
return Emval.toHandle(emGlobalThis[name]);
},
_emval_get_module_property__deps: ['$getStringOrSymbol', '$Emval'],
_emval_get_module_property: (name) => {
name = getStringOrSymbol(name);
return Emval.toHandle(Module[name]);
},
_emval_get_property__deps: ['$Emval'],
_emval_get_property: (handle, key) => {
handle = Emval.toValue(handle);
key = Emval.toValue(key);
return Emval.toHandle(handle[key]);
},
_emval_set_property__deps: ['$Emval'],
_emval_set_property: (handle, key, value) => {
handle = Emval.toValue(handle);
key = Emval.toValue(key);
value = Emval.toValue(value);
handle[key] = value;
},
$emval_returnValue__deps: ['$Emval'],
$emval_returnValue: (toReturnWire, destructorsRef, handle) => {
var destructors = [];
var result = toReturnWire(destructors, handle);
if (destructors.length) {
{{{ makeSetValue('destructorsRef', '0', 'Emval.toHandle(destructors)', '*') }}};
}
return result;
},
_emval_equals__deps: ['$Emval'],
_emval_equals: (first, second) => {
first = Emval.toValue(first);
second = Emval.toValue(second);
return first == second;
},
_emval_strictly_equals__deps: ['$Emval'],
_emval_strictly_equals: (first, second) => {
first = Emval.toValue(first);
second = Emval.toValue(second);
return first === second;
},
_emval_greater_than__deps: ['$Emval'],
_emval_greater_than: (first, second) => {
first = Emval.toValue(first);
second = Emval.toValue(second);
return first > second;
},
_emval_less_than__deps: ['$Emval'],
_emval_less_than: (first, second) => {
first = Emval.toValue(first);
second = Emval.toValue(second);
return first < second;
},
_emval_not__deps: ['$Emval'],
_emval_not: (object) => {
object = Emval.toValue(object);
return !object;
},
$emval_lookupTypes__deps: ['$requireRegisteredType'],
$emval_lookupTypes: (argCount, argTypes) => {
var a = new Array(argCount);
for (var i = 0; i < argCount; ++i) {
a[i] = requireRegisteredType({{{ makeGetValue('argTypes', `i*${POINTER_SIZE}`, '*') }}},
`parameter ${i}`);
}
return a;
},
// Leave id 0 undefined. It's not a big deal, but might be confusing
// to have null be a valid method caller.
$emval_methodCallers: [undefined],
$emval_addMethodCaller__deps: ['$emval_methodCallers'],
$emval_addMethodCaller: (caller) => {
var id = emval_methodCallers.length;
emval_methodCallers.push(caller);
return id;
},
_emval_create_invoker__deps: [
'$emval_addMethodCaller', '$emval_lookupTypes',
'$createNamedFunction', '$emval_returnValue',
'$Emval', '$getStringOrSymbol',
],
_emval_create_invoker: (argCount, argTypesPtr, kind) => {
var GenericWireTypeSize = {{{ 2 * POINTER_SIZE }}};
var [retType, ...argTypes] = emval_lookupTypes(argCount, argTypesPtr);
var toReturnWire = retType.toWireType.bind(retType);
var argFromPtr = argTypes.map(type => type.readValueFromPointer.bind(type));
argCount--; // remove the extracted return type
#if !DYNAMIC_EXECUTION
var argN = new Array(argCount);
var invokerFunction = (handle, methodName, destructorsRef, args) => {
var offset = 0;
for (var i = 0; i < argCount; ++i) {
argN[i] = argFromPtr[i](args + offset);
offset += GenericWireTypeSize;
}
var rv;
switch (kind) {
case {{{ cDefs['internal::EM_INVOKER_KIND::FUNCTION'] }}}:
rv = Emval.toValue(handle).apply(null, argN);
break;
case {{{ cDefs['internal::EM_INVOKER_KIND::CONSTRUCTOR'] }}}:
rv = Reflect.construct(Emval.toValue(handle), argN);
break;
case {{{ cDefs['internal::EM_INVOKER_KIND::CAST'] }}}:
// no-op, just return the argument
rv = argN[0];
break;
case {{{ cDefs['internal::EM_INVOKER_KIND::METHOD'] }}}:
rv = Emval.toValue(handle)[getStringOrSymbol(methodName)](...argN);
break;
}
return emval_returnValue(toReturnWire, destructorsRef, rv);
};
#else
var captures = {'toValue': Emval.toValue};
var args = argFromPtr.map((argFromPtr, i) => {
var captureName = `argFromPtr${i}`;
captures[captureName] = argFromPtr;
return `${captureName}(args${i ? '+' + i * GenericWireTypeSize : ''})`;
});
var functionBody;
switch (kind){
case {{{ cDefs['internal::EM_INVOKER_KIND::FUNCTION'] }}}:
functionBody = 'toValue(handle)';
break;
case {{{ cDefs['internal::EM_INVOKER_KIND::CONSTRUCTOR'] }}}:
functionBody = 'new (toValue(handle))';
break;
case {{{ cDefs['internal::EM_INVOKER_KIND::CAST'] }}}:
functionBody = '';
break;
case {{{ cDefs['internal::EM_INVOKER_KIND::METHOD'] }}}:
captures['getStringOrSymbol'] = getStringOrSymbol;
functionBody = 'toValue(handle)[getStringOrSymbol(methodName)]';
break;
}
functionBody += `(${args})`;
if (!retType.isVoid) {
captures['toReturnWire'] = toReturnWire;
captures['emval_returnValue'] = emval_returnValue;
functionBody = `return emval_returnValue(toReturnWire, destructorsRef, ${functionBody})`;
}
functionBody = `return function (handle, methodName, destructorsRef, args) {
${functionBody}
}`;
var invokerFunction = new Function(Object.keys(captures), functionBody)(...Object.values(captures));
#endif
var functionName = `methodCaller<(${argTypes.map(t => t.name)}) => ${retType.name}>`;
return emval_addMethodCaller(createNamedFunction(functionName, invokerFunction));
},
_emval_invoke__deps: ['$getStringOrSymbol', '$emval_methodCallers', '$Emval'],
_emval_invoke: (caller, handle, methodName, destructorsRef, args) => {
return emval_methodCallers[caller](handle, methodName, destructorsRef, args);
},
// Same as `_emval_invoke`, just imported into Wasm under a different return type.
// TODO: remove this if/when https://github.com/emscripten-core/emscripten/issues/20478 is fixed.
_emval_invoke_i64__deps: ['_emval_invoke'],
_emval_invoke_i64: '=__emval_invoke',
_emval_typeof__deps: ['$Emval'],
_emval_typeof: (handle) => {
handle = Emval.toValue(handle);
return Emval.toHandle(typeof handle);
},
_emval_instanceof__deps: ['$Emval'],
_emval_instanceof: (object, constructor) => {
object = Emval.toValue(object);
constructor = Emval.toValue(constructor);
return object instanceof constructor;
},
_emval_is_number__deps: ['$Emval'],
_emval_is_number: (handle) => {
handle = Emval.toValue(handle);
return typeof handle == 'number';
},
_emval_is_string__deps: ['$Emval'],
_emval_is_string: (handle) => {
handle = Emval.toValue(handle);
return typeof handle == 'string';
},
_emval_in__deps: ['$Emval'],
_emval_in: (item, object) => {
item = Emval.toValue(item);
object = Emval.toValue(object);
return item in object;
},
_emval_delete__deps: ['$Emval'],
_emval_delete: (object, property) => {
object = Emval.toValue(object);
property = Emval.toValue(property);
return delete object[property];
},
_emval_throw__deps: ['$Emval'],
_emval_throw: (object) => {
object = Emval.toValue(object);
throw object;
},
#if ASYNCIFY
_emval_await__deps: ['$Emval', '$Asyncify'],
_emval_await__async: true,
_emval_await: (promise) => {
return Asyncify.handleAsync(async () => {
var value = await Emval.toValue(promise);
return Emval.toHandle(value);
});
},
#endif
_emval_iter_begin__deps: ['$Emval'],
_emval_iter_begin: (iterable) => {
iterable = Emval.toValue(iterable);
return Emval.toHandle(iterable[Symbol.iterator]());
},
_emval_iter_next__deps: ['$Emval'],
_emval_iter_next: (iterator) => {
iterator = Emval.toValue(iterator);
var result = iterator.next();
return result.done ? 0 : Emval.toHandle(result.value);
},
_emval_coro_suspend__deps: ['$Emval', '_emval_coro_resume', '_emval_coro_reject'],
_emval_coro_suspend: (promiseHandle, awaiterPtr) => {
Emval.toValue(promiseHandle)
.then((result) => __emval_coro_resume(awaiterPtr, Emval.toHandle(result)),
(error) => __emval_coro_reject(awaiterPtr, Emval.toHandle(error)));
},
_emval_coro_make_promise__deps: ['$Emval'],
_emval_coro_make_promise: (resolveHandlePtr, rejectHandlePtr) => {
return Emval.toHandle(new Promise((resolve, reject) => {
{{{ makeSetValue('resolveHandlePtr', '0', 'Emval.toHandle(resolve)', '*') }}};
{{{ makeSetValue('rejectHandlePtr', '0', 'Emval.toHandle(reject)', '*') }}};
}));
},
_emval_from_current_cxa_exception__deps: ['$Emval', '__cxa_rethrow'],
_emval_from_current_cxa_exception: () => {
try {
// Use __cxa_rethrow which already has mechanism for generating
// user-friendly error message and stacktrace from C++ exception
// if EXCEPTION_STACK_TRACES is enabled and numeric exception
// with metadata optimised out otherwise.
___cxa_rethrow();
} catch (e) {
return Emval.toHandle(e);
}
},
};
addToLibrary(LibraryEmVal);