| // Copyright 2012 The Emscripten Authors. All rights reserved. |
| // Emscripten is available under two separate licenses, the MIT license and the |
| // University of Illinois/NCSA Open Source License. Both these licenses can be |
| // found in the LICENSE file. |
| |
| /*global Module:true, Runtime*/ |
| /*global HEAP32*/ |
| /*global new_*/ |
| /*global createNamedFunction*/ |
| /*global readLatin1String, stringToUTF8*/ |
| /*global requireRegisteredType, throwBindingError, runDestructors*/ |
| /*jslint sub:true*/ /* The symbols 'fromWireType' and 'toWireType' must be accessed via array notation to be closure-safe since craftInvokerFunction crafts functions as strings that can't be closured. */ |
| |
| // -- jshint doesn't understand library syntax, so we need to mark the symbols exposed here |
| /*global getStringOrSymbol, emval_handle_array, Emval, __emval_unregister, count_emval_handles, emval_symbols, emval_free_list, get_first_emval, __emval_decref, emval_newers*/ |
| /*global craftEmvalAllocator, emval_addMethodCaller, emval_methodCallers, LibraryManager, mergeInto, emval_allocateDestructors, global, emval_lookupTypes, makeLegalFunctionName*/ |
| /*global emval_get_global*/ |
| |
| var LibraryEmVal = { |
| $emval_handle_array: [ |
| {}, |
| {value: undefined}, |
| {value: null}, |
| {value: true}, |
| {value: false} |
| ], // reserve zero and special values |
| $emval_free_list: [], |
| $emval_symbols: {}, // address -> string |
| |
| $init_emval__deps: ['$count_emval_handles', '$get_first_emval'], |
| $init_emval__postset: 'init_emval();', |
| $init_emval: function() { |
| Module['count_emval_handles'] = count_emval_handles; |
| Module['get_first_emval'] = get_first_emval; |
| }, |
| |
| $count_emval_handles__deps: ['$emval_handle_array'], |
| $count_emval_handles: function() { |
| var count = 0; |
| for (var i = 5; i < emval_handle_array.length; ++i) { |
| if (emval_handle_array[i] !== undefined) { |
| ++count; |
| } |
| } |
| return count; |
| }, |
| |
| $get_first_emval__deps: ['$emval_handle_array'], |
| $get_first_emval: function() { |
| for (var i = 5; i < emval_handle_array.length; ++i) { |
| if (emval_handle_array[i] !== undefined) { |
| return emval_handle_array[i]; |
| } |
| } |
| return null; |
| }, |
| |
| _emval_register_symbol__deps: ['$emval_symbols', '$readLatin1String'], |
| _emval_register_symbol: function(address) { |
| emval_symbols[address] = readLatin1String(address); |
| }, |
| |
| $getStringOrSymbol__deps: ['$emval_symbols', '$readLatin1String'], |
| $getStringOrSymbol: function(address) { |
| var symbol = emval_symbols[address]; |
| if (symbol === undefined) { |
| return readLatin1String(address); |
| } |
| return symbol; |
| }, |
| |
| $Emval__deps: ['$emval_handle_array', '$emval_free_list', '$throwBindingError', '$init_emval'], |
| $Emval: { |
| toValue: (handle) => { |
| if (!handle) { |
| throwBindingError('Cannot use deleted val. handle = ' + handle); |
| } |
| return emval_handle_array[handle].value; |
| }, |
| |
| toHandle: (value) => { |
| switch (value) { |
| case undefined: return 1; |
| case null: return 2; |
| case true: return 3; |
| case false: return 4; |
| default:{ |
| var handle = emval_free_list.length ? |
| emval_free_list.pop() : |
| emval_handle_array.length; |
| |
| emval_handle_array[handle] = {refcount: 1, value: value}; |
| return handle; |
| } |
| } |
| } |
| }, |
| |
| _emval_incref__sig: 'vp', |
| _emval_incref__deps: ['$emval_handle_array'], |
| _emval_incref: function(handle) { |
| if (handle > 4) { |
| emval_handle_array[handle].refcount += 1; |
| } |
| }, |
| |
| _emval_decref__sig: 'vp', |
| _emval_decref__deps: ['$emval_free_list', '$emval_handle_array'], |
| _emval_decref: function(handle) { |
| if (handle > 4 && 0 === --emval_handle_array[handle].refcount) { |
| emval_handle_array[handle] = undefined; |
| emval_free_list.push(handle); |
| } |
| }, |
| |
| _emval_run_destructors__sig: 'vp', |
| _emval_run_destructors__deps: ['_emval_decref', '$Emval', '$runDestructors'], |
| _emval_run_destructors: function(handle) { |
| var destructors = Emval.toValue(handle); |
| runDestructors(destructors); |
| __emval_decref(handle); |
| }, |
| |
| _emval_new_array__sig: 'p', |
| _emval_new_array__deps: ['$Emval'], |
| _emval_new_array: function() { |
| return Emval.toHandle([]); |
| }, |
| |
| _emval_new_array_from_memory_view__sig: 'pp', |
| _emval_new_array_from_memory_view__deps: ['$Emval'], |
| _emval_new_array_from_memory_view: function(view) { |
| view = Emval.toValue(view); |
| // using for..loop is faster than Array.from |
| 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__sig: 'p', |
| _emval_new_object__deps: ['$Emval'], |
| _emval_new_object: function() { |
| return Emval.toHandle({}); |
| }, |
| |
| _emval_new_cstring__sig: 'pp', |
| _emval_new_cstring__deps: ['$getStringOrSymbol', '$Emval'], |
| _emval_new_cstring: function(v) { |
| return Emval.toHandle(getStringOrSymbol(v)); |
| }, |
| |
| _emval_new_u8string__sig: 'pp', |
| _emval_new_u8string__deps: ['$Emval'], |
| _emval_new_u8string: function(v) { |
| return Emval.toHandle(UTF8ToString(v)); |
| }, |
| |
| _emval_new_u16string__sig: 'pp', |
| _emval_new_u16string__deps: ['$Emval'], |
| _emval_new_u16string: function(v) { |
| return Emval.toHandle(UTF16ToString(v)); |
| }, |
| |
| _emval_take_value__sig: 'ppp', |
| _emval_take_value__deps: ['$Emval', '$requireRegisteredType'], |
| _emval_take_value: function(type, arg) { |
| type = requireRegisteredType(type, '_emval_take_value'); |
| var v = type['readValueFromPointer'](arg); |
| return Emval.toHandle(v); |
| }, |
| |
| $emval_newers: {}, // arity -> function |
| $craftEmvalAllocator__deps: ['$Emval', '$requireRegisteredType'], |
| $craftEmvalAllocator: function(argCount) { |
| /*This function returns a new function that looks like this: |
| function emval_allocator_3(constructor, argTypes, args) { |
| var argType0 = requireRegisteredType(HEAP32[(argTypes >> 2)], "parameter 0"); |
| var arg0 = argType0['readValueFromPointer'](args); |
| var argType1 = requireRegisteredType(HEAP32[(argTypes >> 2) + 1], "parameter 1"); |
| var arg1 = argType1['readValueFromPointer'](args + 8); |
| var argType2 = requireRegisteredType(HEAP32[(argTypes >> 2) + 2], "parameter 2"); |
| var arg2 = argType2['readValueFromPointer'](args + 16); |
| var obj = new constructor(arg0, arg1, arg2); |
| return Emval.toHandle(obj); |
| } */ |
| #if !DYNAMIC_EXECUTION |
| var argsList = new Array(argCount + 1); |
| return function(constructor, argTypes, args) { |
| argsList[0] = constructor; |
| for (var i = 0; i < argCount; ++i) { |
| var argType = requireRegisteredType({{{ makeGetValue('argTypes', 'i * ' + POINTER_SIZE, '*') }}}, 'parameter ' + i); |
| argsList[i + 1] = argType['readValueFromPointer'](args); |
| args += argType['argPackAdvance']; |
| } |
| var obj = new (constructor.bind.apply(constructor, argsList)); |
| return Emval.toHandle(obj); |
| }; |
| #else |
| var argsList = ""; |
| for (var i = 0; i < argCount; ++i) { |
| argsList += (i!==0?", ":"")+"arg"+i; // 'arg0, arg1, ..., argn' |
| } |
| |
| // The body of the generated function does not have access to enclosing |
| // scope where HEAPU64/HEAPU32/etc are defined, and we cannot pass them |
| // directly as arguments (like we do the Module object) since memory |
| // growth can cause them to be re-bound. |
| var getMemory = () => {{{ MEMORY64 ? "HEAPU64" : "HEAPU32" }}}; |
| |
| var functionBody = |
| "return function emval_allocator_"+argCount+"(constructor, argTypes, args) {\n" + |
| " var {{{ MEMORY64 ? 'HEAPU64' : 'HEAPU32' }}} = getMemory();\n"; |
| |
| for (var i = 0; i < argCount; ++i) { |
| functionBody += |
| "var argType"+i+" = requireRegisteredType({{{ makeGetValue('argTypes', '0', '*') }}}, 'parameter "+i+"');\n" + |
| "var arg"+i+" = argType"+i+".readValueFromPointer(args);\n" + |
| "args += argType"+i+"['argPackAdvance'];\n" + |
| "argTypes += {{{ POINTER_SIZE }}};\n"; |
| } |
| functionBody += |
| "var obj = new constructor("+argsList+");\n" + |
| "return valueToHandle(obj);\n" + |
| "}\n"; |
| |
| /*jshint evil:true*/ |
| return (new Function("requireRegisteredType", "Module", "valueToHandle", "getMemory" , functionBody))( |
| requireRegisteredType, Module, Emval.toHandle, getMemory); |
| #endif |
| }, |
| |
| _emval_new__sig: 'ppipp', |
| _emval_new__deps: ['$craftEmvalAllocator', '$emval_newers', '$Emval'], |
| _emval_new: function(handle, argCount, argTypes, args) { |
| handle = Emval.toValue(handle); |
| |
| var newer = emval_newers[argCount]; |
| if (!newer) { |
| newer = craftEmvalAllocator(argCount); |
| emval_newers[argCount] = newer; |
| } |
| |
| return newer(handle, argTypes, args); |
| }, |
| |
| #if !DYNAMIC_EXECUTION |
| $emval_get_global: function() { |
| if (typeof globalThis == 'object') { |
| return globalThis; |
| } |
| function testGlobal(obj) { |
| obj['$$$embind_global$$$'] = obj; |
| var success = typeof $$$embind_global$$$ == 'object' && obj['$$$embind_global$$$'] == obj; |
| if (!success) { |
| delete obj['$$$embind_global$$$']; |
| } |
| return success; |
| } |
| if (typeof $$$embind_global$$$ == 'object') { |
| return $$$embind_global$$$; |
| } |
| if (typeof global == 'object' && testGlobal(global)) { |
| $$$embind_global$$$ = global; |
| } else if (typeof self == 'object' && testGlobal(self)) { |
| $$$embind_global$$$ = self; // This works for both "window" and "self" (Web Workers) global objects |
| } |
| if (typeof $$$embind_global$$$ == 'object') { |
| return $$$embind_global$$$; |
| } |
| throw Error('unable to get global object.'); |
| }, |
| #else |
| // appease jshint (technically this code uses eval) |
| $emval_get_global: function() { |
| if (typeof globalThis == 'object') { |
| return globalThis; |
| } |
| return (function(){ |
| return Function; |
| })()('return this')(); |
| }, |
| #endif |
| _emval_get_global__sig: 'pp', |
| _emval_get_global__deps: ['$Emval', '$getStringOrSymbol', '$emval_get_global'], |
| _emval_get_global: function(name) { |
| if (name===0) { |
| return Emval.toHandle(emval_get_global()); |
| } else { |
| name = getStringOrSymbol(name); |
| return Emval.toHandle(emval_get_global()[name]); |
| } |
| }, |
| |
| _emval_get_module_property__sig: 'pp', |
| _emval_get_module_property__deps: ['$getStringOrSymbol', '$Emval'], |
| _emval_get_module_property: function(name) { |
| name = getStringOrSymbol(name); |
| return Emval.toHandle(Module[name]); |
| }, |
| |
| _emval_get_property__sig: 'ppp', |
| _emval_get_property__deps: ['$Emval'], |
| _emval_get_property: function(handle, key) { |
| handle = Emval.toValue(handle); |
| key = Emval.toValue(key); |
| return Emval.toHandle(handle[key]); |
| }, |
| |
| _emval_set_property__sig: 'vppp', |
| _emval_set_property__deps: ['$Emval'], |
| _emval_set_property: function(handle, key, value) { |
| handle = Emval.toValue(handle); |
| key = Emval.toValue(key); |
| value = Emval.toValue(value); |
| handle[key] = value; |
| }, |
| |
| _emval_as__sig: 'dppp', |
| _emval_as__deps: ['$Emval', '$requireRegisteredType'], |
| _emval_as: function(handle, returnType, destructorsRef) { |
| handle = Emval.toValue(handle); |
| returnType = requireRegisteredType(returnType, 'emval::as'); |
| var destructors = []; |
| var rd = Emval.toHandle(destructors); |
| {{{ makeSetValue('destructorsRef', '0', 'rd', '*') }}}; |
| return returnType['toWireType'](destructors, handle); |
| }, |
| |
| _emval_as_int64__deps: ['$Emval', '$requireRegisteredType'], |
| _emval_as_int64__sig: 'dppp', |
| _emval_as_int64: function(handle, returnType, destructorsRef) { |
| handle = Emval.toValue(handle); |
| returnType = requireRegisteredType(returnType, 'emval::as'); |
| return returnType['toWireType'](null, handle); |
| }, |
| |
| _emval_as_uint64__deps: ['$Emval', '$requireRegisteredType'], |
| _emval_as_uint64__sig: 'dppp', |
| _emval_as_uint64: function(handle, returnType, destructorsRef) { |
| handle = Emval.toValue(handle); |
| returnType = requireRegisteredType(returnType, 'emval::as'); |
| return returnType['toWireType'](null, handle); |
| }, |
| |
| _emval_equals__deps: ['$Emval'], |
| _emval_equals__sig: 'ipp', |
| _emval_equals: function(first, second) { |
| first = Emval.toValue(first); |
| second = Emval.toValue(second); |
| return first == second; |
| }, |
| |
| _emval_strictly_equals__deps: ['$Emval'], |
| _emval_strictly_equals__sig: 'ipp', |
| _emval_strictly_equals: function(first, second) { |
| first = Emval.toValue(first); |
| second = Emval.toValue(second); |
| return first === second; |
| }, |
| |
| _emval_greater_than__deps: ['$Emval'], |
| _emval_greater_than__sig: 'ipp', |
| _emval_greater_than: function(first, second) { |
| first = Emval.toValue(first); |
| second = Emval.toValue(second); |
| return first > second; |
| }, |
| |
| _emval_less_than__deps: ['$Emval'], |
| _emval_less_than__sig: 'ipp', |
| _emval_less_than: function(first, second) { |
| first = Emval.toValue(first); |
| second = Emval.toValue(second); |
| return first < second; |
| }, |
| |
| _emval_not__deps: ['$Emval'], |
| _emval_not__sig: 'ip', |
| _emval_not: function(object) { |
| object = Emval.toValue(object); |
| return !object; |
| }, |
| |
| _emval_call__sig: 'ppppp', |
| _emval_call__deps: ['$emval_lookupTypes', '$Emval'], |
| _emval_call: function(handle, argCount, argTypes, argv) { |
| handle = Emval.toValue(handle); |
| var types = emval_lookupTypes(argCount, argTypes); |
| |
| var args = new Array(argCount); |
| for (var i = 0; i < argCount; ++i) { |
| var type = types[i]; |
| args[i] = type['readValueFromPointer'](argv); |
| argv += type['argPackAdvance']; |
| } |
| |
| var rv = handle.apply(undefined, args); |
| return Emval.toHandle(rv); |
| }, |
| |
| $emval_lookupTypes__deps: ['$requireRegisteredType'], |
| $emval_lookupTypes: function(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; |
| }, |
| |
| $emval_allocateDestructors__deps: ['$Emval'], |
| $emval_allocateDestructors: function(destructorsRef) { |
| var destructors = []; |
| {{{ makeSetValue('destructorsRef', '0', 'Emval.toHandle(destructors)', '*') }}}; |
| return destructors; |
| }, |
| |
| // 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: function(caller) { |
| var id = emval_methodCallers.length; |
| emval_methodCallers.push(caller); |
| return id; |
| }, |
| |
| $emval_registeredMethods: [], |
| _emval_get_method_caller__sig: 'ppp', |
| _emval_get_method_caller__deps: ['$emval_addMethodCaller', '$emval_lookupTypes', '$new_', '$makeLegalFunctionName', '$emval_registeredMethods'], |
| _emval_get_method_caller: function(argCount, argTypes) { |
| var types = emval_lookupTypes(argCount, argTypes); |
| var retType = types[0]; |
| var signatureName = retType.name + "_$" + types.slice(1).map(function (t) { return t.name; }).join("_") + "$"; |
| var returnId = emval_registeredMethods[signatureName]; |
| if (returnId !== undefined) { |
| return returnId; |
| } |
| |
| #if !DYNAMIC_EXECUTION |
| var argN = new Array(argCount - 1); |
| var invokerFunction = (handle, name, destructors, args) => { |
| var offset = 0; |
| for (var i = 0; i < argCount - 1; ++i) { |
| argN[i] = types[i + 1]['readValueFromPointer'](args + offset); |
| offset += types[i + 1]['argPackAdvance']; |
| } |
| var rv = handle[name].apply(handle, argN); |
| for (var i = 0; i < argCount - 1; ++i) { |
| if (types[i + 1].deleteObject) { |
| types[i + 1].deleteObject(argN[i]); |
| } |
| } |
| if (!retType.isVoid) { |
| return retType['toWireType'](destructors, rv); |
| } |
| }; |
| #else |
| var params = ["retType"]; |
| var args = [retType]; |
| |
| var argsList = ""; // 'arg0, arg1, arg2, ... , argN' |
| for (var i = 0; i < argCount - 1; ++i) { |
| argsList += (i !== 0 ? ", " : "") + "arg" + i; |
| params.push("argType" + i); |
| args.push(types[1 + i]); |
| } |
| |
| var functionName = makeLegalFunctionName("methodCaller_" + signatureName); |
| var functionBody = |
| "return function " + functionName + "(handle, name, destructors, args) {\n"; |
| |
| var offset = 0; |
| for (var i = 0; i < argCount - 1; ++i) { |
| functionBody += |
| " var arg" + i + " = argType" + i + ".readValueFromPointer(args" + (offset ? ("+"+offset) : "") + ");\n"; |
| offset += types[i + 1]['argPackAdvance']; |
| } |
| functionBody += |
| " var rv = handle[name](" + argsList + ");\n"; |
| for (var i = 0; i < argCount - 1; ++i) { |
| if (types[i + 1]['deleteObject']) { |
| functionBody += |
| " argType" + i + ".deleteObject(arg" + i + ");\n"; |
| } |
| } |
| if (!retType.isVoid) { |
| functionBody += |
| " return retType.toWireType(destructors, rv);\n"; |
| } |
| functionBody += |
| "};\n"; |
| |
| params.push(functionBody); |
| var invokerFunction = new_(Function, params).apply(null, args); |
| #endif |
| returnId = emval_addMethodCaller(invokerFunction); |
| emval_registeredMethods[signatureName] = returnId; |
| return returnId; |
| }, |
| |
| _emval_call_method__deps: ['$emval_allocateDestructors', '$getStringOrSymbol', '$emval_methodCallers', '$Emval'], |
| _emval_call_method__sig: 'dppppp', |
| _emval_call_method: function(caller, handle, methodName, destructorsRef, args) { |
| caller = emval_methodCallers[caller]; |
| handle = Emval.toValue(handle); |
| methodName = getStringOrSymbol(methodName); |
| return caller(handle, methodName, emval_allocateDestructors(destructorsRef), args); |
| }, |
| |
| _emval_call_void_method__sig: 'vpppp', |
| _emval_call_void_method__deps: ['$emval_allocateDestructors', '$getStringOrSymbol', '$emval_methodCallers', '$Emval'], |
| _emval_call_void_method: function(caller, handle, methodName, args) { |
| caller = emval_methodCallers[caller]; |
| handle = Emval.toValue(handle); |
| methodName = getStringOrSymbol(methodName); |
| caller(handle, methodName, null, args); |
| }, |
| |
| _emval_typeof__sig: 'pp', |
| _emval_typeof__deps: ['$Emval'], |
| _emval_typeof: function(handle) { |
| handle = Emval.toValue(handle); |
| return Emval.toHandle(typeof handle); |
| }, |
| |
| _emval_instanceof__deps: ['$Emval'], |
| _emval_instanceof__sig: 'ipp', |
| _emval_instanceof: function(object, constructor) { |
| object = Emval.toValue(object); |
| constructor = Emval.toValue(constructor); |
| return object instanceof constructor; |
| }, |
| |
| _emval_is_number__deps: ['$Emval'], |
| _emval_is_number__sig: 'ip', |
| _emval_is_number: function(handle) { |
| handle = Emval.toValue(handle); |
| return typeof handle == 'number'; |
| }, |
| |
| _emval_is_string__deps: ['$Emval'], |
| _emval_is_string__sig: 'ip', |
| _emval_is_string: function(handle) { |
| handle = Emval.toValue(handle); |
| return typeof handle == 'string'; |
| }, |
| |
| _emval_in__deps: ['$Emval'], |
| _emval_in__sig: 'ipp', |
| _emval_in: function(item, object) { |
| item = Emval.toValue(item); |
| object = Emval.toValue(object); |
| return item in object; |
| }, |
| |
| _emval_delete__deps: ['$Emval'], |
| _emval_delete__sig: 'ipp', |
| _emval_delete: function(object, property) { |
| object = Emval.toValue(object); |
| property = Emval.toValue(property); |
| return delete object[property]; |
| }, |
| |
| _emval_throw__deps: ['$Emval'], |
| _emval_throw__sig: 'vp', |
| _emval_throw: function(object) { |
| object = Emval.toValue(object); |
| throw object; |
| }, |
| |
| #if ASYNCIFY |
| _emval_await__deps: ['$Emval', '$Asyncify'], |
| _emval_await: function(promise) { |
| return Asyncify.handleAsync(() => { |
| promise = Emval.toValue(promise); |
| return promise.then(Emval.toHandle); |
| }); |
| }, |
| #endif |
| }; |
| |
| mergeInto(LibraryManager.library, LibraryEmVal); |