Buckets:
| // 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. | |
| #include "libembind_shared.js" | |
| var LibraryEmbind = { | |
| $UnboundTypeError: class extends Error {}, | |
| $PureVirtualError: class extends Error {}, | |
| #if EMBIND_AOT | |
| $InvokerFunctions: '<<< EMBIND_AOT_INVOKERS >>>', | |
| #endif | |
| // If register_type is used, emval will be registered multiple times for | |
| // different type ids, but only a single type object is needed on the JS side | |
| // for all of them. Store the type for reuse. | |
| $EmValType__deps: ['_emval_decref', '$Emval', '$readPointer'], | |
| $EmValType: `{ | |
| name: 'emscripten::val', | |
| fromWireType: (handle) => { | |
| var rv = Emval.toValue(handle); | |
| __emval_decref(handle); | |
| return rv; | |
| }, | |
| toWireType: (destructors, value) => Emval.toHandle(value), | |
| readValueFromPointer: readPointer, | |
| destructorFunction: null, // This type does not need a destructor | |
| // TODO: do we need a deleteObject here? write a test where | |
| // emval is passed into JS via an interface | |
| }`, | |
| $EmValOptionalType__deps: ['$EmValType'], | |
| $EmValOptionalType: '=Object.assign({optional: true}, EmValType);', | |
| $throwUnboundTypeError__deps: ['$registeredTypes', '$typeDependencies', '$UnboundTypeError', '$getTypeName'], | |
| $throwUnboundTypeError: (message, types) => { | |
| var unboundTypes = []; | |
| var seen = {}; | |
| function visit(type) { | |
| if (seen[type]) { | |
| return; | |
| } | |
| if (registeredTypes[type]) { | |
| return; | |
| } | |
| if (typeDependencies[type]) { | |
| typeDependencies[type].forEach(visit); | |
| return; | |
| } | |
| unboundTypes.push(type); | |
| seen[type] = true; | |
| } | |
| types.forEach(visit); | |
| throw new UnboundTypeError(`${message}: ` + unboundTypes.map(getTypeName).join([', '])); | |
| }, | |
| // Creates a function overload resolution table to the given method 'methodName' in the given prototype, | |
| // if the overload table doesn't yet exist. | |
| $ensureOverloadTable__deps: ['$throwBindingError'], | |
| $ensureOverloadTable: (proto, methodName, humanName) => { | |
| if (undefined === proto[methodName].overloadTable) { | |
| var prevFunc = proto[methodName]; | |
| // Inject an overload resolver function that routes to the appropriate overload based on the number of arguments. | |
| proto[methodName] = function(...args) { | |
| // TODO This check can be removed in -O3 level "unsafe" optimizations. | |
| if (!proto[methodName].overloadTable.hasOwnProperty(args.length)) { | |
| throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${args.length}) - expects one of (${proto[methodName].overloadTable})!`); | |
| } | |
| return proto[methodName].overloadTable[args.length].apply(this, args); | |
| }; | |
| // Move the previous function into the overload table. | |
| proto[methodName].overloadTable = []; | |
| proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; | |
| } | |
| }, | |
| /* | |
| Registers a symbol (function, class, enum, ...) as part of the Module JS object so that | |
| hand-written code is able to access that symbol via 'Module.name'. | |
| name: The name of the symbol that's being exposed. | |
| value: The object itself to expose (function, class, ...) | |
| numArguments: For functions, specifies the number of arguments the function takes in. For other types, unused and undefined. | |
| To implement support for multiple overloads of a function, an 'overload selector' function is used. That selector function chooses | |
| the appropriate overload to call from an function overload table. This selector function is only used if multiple overloads are | |
| actually registered, since it carries a slight performance penalty. */ | |
| $exposePublicSymbol__deps: ['$ensureOverloadTable', '$throwBindingError'], | |
| $exposePublicSymbol__docs: '/** @param {number=} numArguments */', | |
| $exposePublicSymbol: (name, value, numArguments) => { | |
| if (Module.hasOwnProperty(name)) { | |
| if (undefined === numArguments || (undefined !== Module[name].overloadTable && undefined !== Module[name].overloadTable[numArguments])) { | |
| throwBindingError(`Cannot register public name '${name}' twice`); | |
| } | |
| // We are exposing a function with the same name as an existing function. Create an overload table and a function selector | |
| // that routes between the two. | |
| ensureOverloadTable(Module, name, name); | |
| if (Module[name].overloadTable.hasOwnProperty(numArguments)) { | |
| throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`); | |
| } | |
| // Add the new function into the overload table. | |
| Module[name].overloadTable[numArguments] = value; | |
| } else { | |
| Module[name] = value; | |
| Module[name].argCount = numArguments; | |
| } | |
| }, | |
| $replacePublicSymbol__deps: ['$throwInternalError'], | |
| $replacePublicSymbol__docs: '/** @param {number=} numArguments */', | |
| $replacePublicSymbol: (name, value, numArguments) => { | |
| if (!Module.hasOwnProperty(name)) { | |
| throwInternalError('Replacing nonexistent public symbol'); | |
| } | |
| // If there's an overload table for this symbol, replace the symbol in the overload table instead. | |
| if (undefined !== Module[name].overloadTable && undefined !== numArguments) { | |
| Module[name].overloadTable[numArguments] = value; | |
| } else { | |
| Module[name] = value; | |
| Module[name].argCount = numArguments; | |
| } | |
| }, | |
| $embindRepr: (v) => { | |
| if (v === null) { | |
| return 'null'; | |
| } | |
| var t = typeof v; | |
| if (t === 'object' || t === 'array' || t === 'function') { | |
| return v.toString(); | |
| } else { | |
| return '' + v; | |
| } | |
| }, | |
| // raw pointer -> instance | |
| $registeredInstances: {}, | |
| $getBasestPointer__deps: ['$throwBindingError'], | |
| $getBasestPointer: (class_, ptr) => { | |
| if (ptr === undefined) { | |
| throwBindingError('ptr should not be undefined'); | |
| } | |
| while (class_.baseClass) { | |
| ptr = class_.upcast(ptr); | |
| class_ = class_.baseClass; | |
| } | |
| return ptr; | |
| }, | |
| $registerInheritedInstance__deps: ['$registeredInstances', '$getBasestPointer', '$throwBindingError'], | |
| $registerInheritedInstance: (class_, ptr, instance) => { | |
| ptr = getBasestPointer(class_, ptr); | |
| if (registeredInstances.hasOwnProperty(ptr)) { | |
| throwBindingError(`Tried to register registered instance: ${ptr}`); | |
| } else { | |
| registeredInstances[ptr] = instance; | |
| } | |
| }, | |
| $unregisterInheritedInstance__deps: ['$registeredInstances', '$getBasestPointer', '$throwBindingError'], | |
| $unregisterInheritedInstance: (class_, ptr) => { | |
| ptr = getBasestPointer(class_, ptr); | |
| if (registeredInstances.hasOwnProperty(ptr)) { | |
| delete registeredInstances[ptr]; | |
| } else { | |
| throwBindingError(`Tried to unregister unregistered instance: ${ptr}`); | |
| } | |
| }, | |
| $getInheritedInstance__deps: ['$registeredInstances', '$getBasestPointer'], | |
| $getInheritedInstance: (class_, ptr) => { | |
| ptr = getBasestPointer(class_, ptr); | |
| return registeredInstances[ptr]; | |
| }, | |
| $getInheritedInstanceCount__deps: ['$registeredInstances'], | |
| $getInheritedInstanceCount: () => Object.keys(registeredInstances).length, | |
| $getLiveInheritedInstances__deps: ['$registeredInstances'], | |
| $getLiveInheritedInstances: () => { | |
| var rv = []; | |
| for (var k in registeredInstances) { | |
| if (registeredInstances.hasOwnProperty(k)) { | |
| rv.push(registeredInstances[k]); | |
| } | |
| } | |
| return rv; | |
| }, | |
| // class typeID -> {pointerType: ..., constPointerType: ...} | |
| $registeredPointers: {}, | |
| $registerType__deps: ['$sharedRegisterType'], | |
| $registerType__docs: '/** @param {Object=} options */', | |
| $registerType: function(rawType, registeredInstance, options = {}) { | |
| return sharedRegisterType(rawType, registeredInstance, options); | |
| }, | |
| _embind_register_void__deps: ['$AsciiToString', '$registerType'], | |
| _embind_register_void: (rawType, name) => { | |
| name = AsciiToString(name); | |
| registerType(rawType, { | |
| isVoid: true, // void return values can be optimized out sometimes | |
| name, | |
| fromWireType: () => undefined, | |
| // TODO: assert if anything else is given? | |
| toWireType: (destructors, o) => undefined, | |
| }); | |
| }, | |
| _embind_register_bool__docs: '/** @suppress {globalThis} */', | |
| _embind_register_bool__deps: ['$AsciiToString', '$registerType'], | |
| _embind_register_bool: (rawType, name, trueValue, falseValue) => { | |
| name = AsciiToString(name); | |
| registerType(rawType, { | |
| name, | |
| fromWireType: function(wt) { | |
| // ambiguous emscripten ABI: sometimes return values are | |
| // true or false, and sometimes integers (0 or 1) | |
| return !!wt; | |
| }, | |
| toWireType: function(destructors, o) { | |
| return o ? trueValue : falseValue; | |
| }, | |
| readValueFromPointer: function(pointer) { | |
| return this.fromWireType(HEAPU8[pointer]); | |
| }, | |
| destructorFunction: null, // This type does not need a destructor | |
| }); | |
| }, | |
| $integerReadValueFromPointer__deps: [], | |
| $integerReadValueFromPointer: (name, width, signed) => { | |
| // integers are quite common, so generate very specialized functions | |
| switch (width) { | |
| case 1: return signed ? | |
| (pointer) => {{{ makeGetValue('pointer', 0, 'i8') }}} : | |
| (pointer) => {{{ makeGetValue('pointer', 0, 'u8') }}}; | |
| case 2: return signed ? | |
| (pointer) => {{{ makeGetValue('pointer', 0, 'i16') }}} : | |
| (pointer) => {{{ makeGetValue('pointer', 0, 'u16') }}} | |
| case 4: return signed ? | |
| (pointer) => {{{ makeGetValue('pointer', 0, 'i32') }}} : | |
| (pointer) => {{{ makeGetValue('pointer', 0, 'u32') }}} | |
| #if WASM_BIGINT | |
| case 8: return signed ? | |
| (pointer) => {{{ makeGetValue('pointer', 0, 'i64') }}} : | |
| (pointer) => {{{ makeGetValue('pointer', 0, 'u64') }}} | |
| #endif | |
| default: | |
| throw new TypeError(`invalid integer width (${width}): ${name}`); | |
| } | |
| }, | |
| $enumReadValueFromPointer__deps: [], | |
| $enumReadValueFromPointer: (name, width, signed) => { | |
| switch (width) { | |
| case 1: return signed ? | |
| function(pointer) { return this.fromWireType({{{ makeGetValue('pointer', 0, 'i8') }}}) } : | |
| function(pointer) { return this.fromWireType({{{ makeGetValue('pointer', 0, 'u8') }}}) }; | |
| case 2: return signed ? | |
| function(pointer) { return this.fromWireType({{{ makeGetValue('pointer', 0, 'i16') }}}) } : | |
| function(pointer) { return this.fromWireType({{{ makeGetValue('pointer', 0, 'u16') }}}) }; | |
| case 4: return signed ? | |
| function(pointer) { return this.fromWireType({{{ makeGetValue('pointer', 0, 'i32') }}}) } : | |
| function(pointer) { return this.fromWireType({{{ makeGetValue('pointer', 0, 'u32') }}}) }; | |
| default: | |
| throw new TypeError(`invalid integer width (${width}): ${name}`); | |
| } | |
| }, | |
| $floatReadValueFromPointer__deps: [], | |
| $floatReadValueFromPointer: (name, width) => { | |
| switch (width) { | |
| case 4: return function(pointer) { | |
| return this.fromWireType({{{ makeGetValue('pointer', 0, 'float') }}}); | |
| }; | |
| case 8: return function(pointer) { | |
| return this.fromWireType({{{ makeGetValue('pointer', 0, 'double') }}}); | |
| }; | |
| default: | |
| throw new TypeError(`invalid float width (${width}): ${name}`); | |
| } | |
| }, | |
| #if ASSERTIONS | |
| $assertIntegerRange__deps: ['$embindRepr'], | |
| $assertIntegerRange: (typeName, value, minRange, maxRange) => { | |
| if (value < minRange || value > maxRange) { | |
| throw new TypeError(`Passing a number "${embindRepr(value)}" from JS side to C/C++ side to an argument of type "${typeName}", which is outside the valid range [${minRange}, ${maxRange}]!`); | |
| } | |
| }, | |
| #endif | |
| _embind_register_integer__docs: '/** @suppress {globalThis} */', | |
| // When converting a number from JS to C++ side, the valid range of the number is | |
| // [minRange, maxRange], inclusive. | |
| _embind_register_integer__deps: [ | |
| '$integerReadValueFromPointer', '$AsciiToString', '$registerType', | |
| #if ASSERTIONS | |
| '$embindRepr', | |
| '$assertIntegerRange', | |
| #endif | |
| ], | |
| _embind_register_integer: (primitiveType, name, size, minRange, maxRange) => { | |
| name = AsciiToString(name); | |
| const isUnsignedType = minRange === 0; | |
| let fromWireType = (value) => value; | |
| if (isUnsignedType) { | |
| var bitshift = 32 - 8*size; | |
| fromWireType = (value) => (value << bitshift) >>> bitshift; | |
| maxRange = fromWireType(maxRange); | |
| } | |
| registerType(primitiveType, { | |
| name, | |
| fromWireType: fromWireType, | |
| toWireType: (destructors, value) => { | |
| #if ASSERTIONS | |
| if (typeof value != "number" && typeof value != "boolean") { | |
| throw new TypeError(`Cannot convert "${embindRepr(value)}" to ${name}`); | |
| } | |
| assertIntegerRange(name, value, minRange, maxRange); | |
| #endif | |
| // The VM will perform JS to Wasm value conversion, according to the spec: | |
| // https://www.w3.org/TR/wasm-js-api-1/#towebassemblyvalue | |
| return value; | |
| }, | |
| readValueFromPointer: integerReadValueFromPointer(name, size, minRange !== 0), | |
| destructorFunction: null, // This type does not need a destructor | |
| }); | |
| }, | |
| #if WASM_BIGINT | |
| _embind_register_bigint__docs: '/** @suppress {globalThis} */', | |
| _embind_register_bigint__deps: [ | |
| '$AsciiToString', '$registerType', '$integerReadValueFromPointer', | |
| #if ASSERTIONS | |
| '$embindRepr', | |
| '$assertIntegerRange', | |
| #endif | |
| ], | |
| _embind_register_bigint: (primitiveType, name, size, minRange, maxRange) => { | |
| name = AsciiToString(name); | |
| const isUnsignedType = minRange === 0n; | |
| let fromWireType = (value) => value; | |
| if (isUnsignedType) { | |
| // uint64 get converted to int64 in ABI, fix them up like we do for 32-bit integers. | |
| const bitSize = size * 8; | |
| fromWireType = (value) => { | |
| #if MEMORY64 | |
| // FIXME(https://github.com/emscripten-core/emscripten/issues/16975) | |
| // `size_t` ends up here, but it's transferred in the ABI as a plain number instead of a bigint. | |
| if (typeof value == 'number') { | |
| return value >>> 0; | |
| } | |
| #endif | |
| return BigInt.asUintN(bitSize, value); | |
| } | |
| maxRange = fromWireType(maxRange); | |
| } | |
| registerType(primitiveType, { | |
| name, | |
| fromWireType: fromWireType, | |
| toWireType: (destructors, value) => { | |
| if (typeof value == "number") { | |
| value = BigInt(value); | |
| } | |
| #if ASSERTIONS | |
| else if (typeof value != "bigint") { | |
| throw new TypeError(`Cannot convert "${embindRepr(value)}" to ${name}`); | |
| } | |
| assertIntegerRange(name, value, minRange, maxRange); | |
| #endif | |
| return value; | |
| }, | |
| readValueFromPointer: integerReadValueFromPointer(name, size, !isUnsignedType), | |
| destructorFunction: null, // This type does not need a destructor | |
| }); | |
| }, | |
| #else | |
| _embind_register_bigint__deps: [], | |
| _embind_register_bigint: (primitiveType, name, size, minRange, maxRange) => {}, | |
| #endif | |
| _embind_register_float__deps: [ | |
| '$floatReadValueFromPointer', '$AsciiToString', '$registerType', | |
| #if ASSERTIONS | |
| '$embindRepr', | |
| #endif | |
| ], | |
| _embind_register_float: (rawType, name, size) => { | |
| name = AsciiToString(name); | |
| registerType(rawType, { | |
| name, | |
| fromWireType: (value) => value, | |
| toWireType: (destructors, value) => { | |
| #if ASSERTIONS | |
| if (typeof value != "number" && typeof value != "boolean") { | |
| throw new TypeError(`Cannot convert ${embindRepr(value)} to ${name}`); | |
| } | |
| #endif | |
| // The VM will perform JS to Wasm value conversion, according to the spec: | |
| // https://www.w3.org/TR/wasm-js-api-1/#towebassemblyvalue | |
| return value; | |
| }, | |
| readValueFromPointer: floatReadValueFromPointer(name, size), | |
| destructorFunction: null, // This type does not need a destructor | |
| }); | |
| }, | |
| $readPointer__docs: '/** @suppress {globalThis} */', | |
| $readPointer: function(pointer) { | |
| return this.fromWireType({{{ makeGetValue('pointer', '0', '*') }}}); | |
| }, | |
| $installIndexedIterator: (proto, sizeMethodName, getMethodName) => { | |
| const makeIterator = (size, getValue) => { | |
| #if MEMORY64 | |
| // size can be either a number or a bigint on wasm64 | |
| const useBigInt = typeof size === 'bigint'; | |
| const one = useBigInt ? 1n : 1; | |
| let index = useBigInt ? 0n : 0; | |
| #else | |
| let index = 0; | |
| #endif | |
| return { | |
| next() { | |
| if (index >= size) { | |
| return { done: true }; | |
| } | |
| const current = index; | |
| #if MEMORY64 | |
| index += one; | |
| #else | |
| index++; | |
| #endif | |
| const value = getValue(current); | |
| return { value, done: false }; | |
| }, | |
| [Symbol.iterator]() { | |
| return this; | |
| }, | |
| }; | |
| }; | |
| if (!proto[Symbol.iterator]) { | |
| proto[Symbol.iterator] = function() { | |
| const size = this[sizeMethodName](); | |
| return makeIterator(size, (i) => this[getMethodName](i)); | |
| }; | |
| } | |
| }, | |
| _embind_register_std_string__deps: [ | |
| '$AsciiToString', '$registerType', | |
| '$readPointer', '$throwBindingError', | |
| '$stringToUTF8', '$lengthBytesUTF8', 'malloc', 'free'], | |
| _embind_register_std_string: (rawType, name) => { | |
| name = AsciiToString(name); | |
| var stdStringIsUTF8 = {{{ EMBIND_STD_STRING_IS_UTF8 }}}; | |
| registerType(rawType, { | |
| name, | |
| // For some method names we use string keys here since they are part of | |
| // the public/external API and/or used by the runtime-generated code. | |
| fromWireType(value) { | |
| var length = {{{ makeGetValue('value', '0', '*') }}}; | |
| var payload = value + {{{ POINTER_SIZE }}}; | |
| var str; | |
| if (stdStringIsUTF8) { | |
| str = UTF8ToString(payload, length, true); | |
| } else { | |
| str = ''; | |
| for (var i = 0; i < length; ++i) { | |
| str += String.fromCharCode(HEAPU8[payload + i]); | |
| } | |
| } | |
| _free(value); | |
| return str; | |
| }, | |
| toWireType(destructors, value) { | |
| if (value instanceof ArrayBuffer) { | |
| value = new Uint8Array(value); | |
| } | |
| var length; | |
| var valueIsOfTypeString = (typeof value == 'string'); | |
| // We accept `string` or array views with single byte elements | |
| if (!(valueIsOfTypeString || (ArrayBuffer.isView(value) && value.BYTES_PER_ELEMENT == 1))) { | |
| throwBindingError('Cannot pass non-string to std::string'); | |
| } | |
| if (stdStringIsUTF8 && valueIsOfTypeString) { | |
| length = lengthBytesUTF8(value); | |
| } else { | |
| length = value.length; | |
| } | |
| // assumes POINTER_SIZE alignment | |
| var base = _malloc({{{ POINTER_SIZE }}} + length + 1); | |
| var ptr = base + {{{ POINTER_SIZE }}}; | |
| {{{ makeSetValue('base', '0', 'length', SIZE_TYPE) }}}; | |
| if (valueIsOfTypeString) { | |
| if (stdStringIsUTF8) { | |
| stringToUTF8(value, ptr, length + 1); | |
| } else { | |
| for (var i = 0; i < length; ++i) { | |
| var charCode = value.charCodeAt(i); | |
| if (charCode > 255) { | |
| _free(base); | |
| throwBindingError('String has UTF-16 code units that do not fit in 8 bits'); | |
| } | |
| HEAPU8[ptr + i] = charCode; | |
| } | |
| } | |
| } else { | |
| HEAPU8.set(value, ptr); | |
| } | |
| if (destructors !== null) { | |
| destructors.push(_free, base); | |
| } | |
| return base; | |
| }, | |
| readValueFromPointer: readPointer, | |
| destructorFunction(ptr) { | |
| _free(ptr); | |
| }, | |
| }); | |
| }, | |
| _embind_register_std_wstring__deps: [ | |
| '$AsciiToString', '$registerType', '$readPointer', | |
| '$UTF16ToString', '$stringToUTF16', '$lengthBytesUTF16', | |
| '$UTF32ToString', '$stringToUTF32', '$lengthBytesUTF32', | |
| ], | |
| _embind_register_std_wstring: (rawType, charSize, name) => { | |
| name = AsciiToString(name); | |
| var decodeString, encodeString, lengthBytesUTF; | |
| if (charSize === 2) { | |
| decodeString = UTF16ToString; | |
| encodeString = stringToUTF16; | |
| lengthBytesUTF = lengthBytesUTF16; | |
| } else { | |
| #if ASSERTIONS | |
| assert(charSize === 4, 'only 2-byte and 4-byte strings are currently supported'); | |
| #endif | |
| decodeString = UTF32ToString; | |
| encodeString = stringToUTF32; | |
| lengthBytesUTF = lengthBytesUTF32; | |
| } | |
| registerType(rawType, { | |
| name, | |
| fromWireType: (value) => { | |
| // Code mostly taken from _embind_register_std_string fromWireType | |
| var length = {{{ makeGetValue('value', 0, '*') }}}; | |
| var str = decodeString(value + {{{ POINTER_SIZE }}}, length * charSize, true); | |
| _free(value); | |
| return str; | |
| }, | |
| toWireType: (destructors, value) => { | |
| if (!(typeof value == 'string')) { | |
| throwBindingError(`Cannot pass non-string to C++ string type ${name}`); | |
| } | |
| // assumes POINTER_SIZE alignment | |
| var length = lengthBytesUTF(value); | |
| var ptr = _malloc({{{ POINTER_SIZE }}} + length + charSize); | |
| {{{ makeSetValue('ptr', '0', 'length / charSize', SIZE_TYPE) }}}; | |
| encodeString(value, ptr + {{{ POINTER_SIZE }}}, length + charSize); | |
| if (destructors !== null) { | |
| destructors.push(_free, ptr); | |
| } | |
| return ptr; | |
| }, | |
| readValueFromPointer: readPointer, | |
| destructorFunction(ptr) { | |
| _free(ptr); | |
| } | |
| }); | |
| }, | |
| _embind_register_emval__deps: [ | |
| '$registerType', '$EmValType'], | |
| _embind_register_emval: (rawType) => registerType(rawType, EmValType), | |
| _embind_register_user_type__deps: ['_embind_register_emval'], | |
| _embind_register_user_type: (rawType, name) => { | |
| __embind_register_emval(rawType); | |
| }, | |
| _embind_register_user_type_definition__deps: ['_embind_register_emval'], | |
| _embind_register_user_type_definition: (rawType, name, definition) => { | |
| __embind_register_emval(rawType); | |
| }, | |
| _embind_register_optional__deps: ['$registerType', '$EmValOptionalType'], | |
| _embind_register_optional: (rawOptionalType, rawType) => { | |
| registerType(rawOptionalType, EmValOptionalType); | |
| }, | |
| _embind_register_memory_view__deps: ['$AsciiToString', '$registerType'], | |
| _embind_register_memory_view: (rawType, dataTypeIndex, name) => { | |
| var typeMapping = [ | |
| Int8Array, | |
| Uint8Array, | |
| Int16Array, | |
| Uint16Array, | |
| Int32Array, | |
| Uint32Array, | |
| Float32Array, | |
| Float64Array, | |
| #if WASM_BIGINT | |
| BigInt64Array, | |
| BigUint64Array, | |
| #endif | |
| ]; | |
| var TA = typeMapping[dataTypeIndex]; | |
| function decodeMemoryView(handle) { | |
| var size = {{{ makeGetValue('handle', 0, '*') }}}; | |
| var data = {{{ makeGetValue('handle', POINTER_SIZE, '*') }}}; | |
| return new TA(HEAP8.buffer, data, size); | |
| } | |
| name = AsciiToString(name); | |
| registerType(rawType, { | |
| name, | |
| fromWireType: decodeMemoryView, | |
| readValueFromPointer: decodeMemoryView, | |
| }, { | |
| ignoreDuplicateRegistrations: true, | |
| }); | |
| }, | |
| $runDestructors: (destructors) => { | |
| while (destructors.length) { | |
| var ptr = destructors.pop(); | |
| var del = destructors.pop(); | |
| del(ptr); | |
| } | |
| }, | |
| // The path to interop from JS code to C++ code: | |
| // (hand-written JS code) -> (autogenerated JS invoker) -> (template-generated C++ invoker) -> (target C++ function) | |
| // craftInvokerFunction generates the JS invoker function for each function exposed to JS through embind. | |
| $craftInvokerFunction__deps: [ | |
| '$createNamedFunction', '$runDestructors', '$throwBindingError', '$usesDestructorStack', | |
| #if DYNAMIC_EXECUTION && !EMBIND_AOT | |
| '$createJsInvoker', | |
| #endif | |
| #if EMBIND_AOT | |
| '$InvokerFunctions', | |
| '$createJsInvokerSignature', | |
| #endif | |
| #if ASYNCIFY == 1 | |
| '$Asyncify', | |
| #endif | |
| #if ASSERTIONS | |
| '$getRequiredArgCount', | |
| '$checkArgCount', | |
| #endif | |
| ], | |
| $craftInvokerFunction: function(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc, /** boolean= */ isAsync) { | |
| // humanName: a human-readable string name for the function to be generated. | |
| // argTypes: An array that contains the embind type objects for all types in the function signature. | |
| // argTypes[0] is the type object for the function return value. | |
| // argTypes[1] is the type object for function this object/class type, or null if not crafting an invoker for a class method. | |
| // argTypes[2...] are the actual function parameters. | |
| // classType: The embind type object for the class to be bound, or null if this is not a method of a class. | |
| // cppInvokerFunc: JS Function object to the C++-side function that interops into C++ code. | |
| // cppTargetFunc: Function pointer (an integer to FUNCTION_TABLE) to the target C++ function the cppInvokerFunc will end up calling. | |
| // isAsync: Optional. If true, returns an async function. Async bindings are only supported with JSPI. | |
| var argCount = argTypes.length; | |
| if (argCount < 2) { | |
| throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!"); | |
| } | |
| #if ASSERTIONS && ASYNCIFY != 2 | |
| assert(!isAsync, 'async bindings are only supported with JSPI'); | |
| #endif | |
| var isClassMethodFunc = (argTypes[1] !== null && classType !== null); | |
| // Free functions with signature "void function()" do not need an invoker that marshalls between wire types. | |
| // TODO: This omits argument count check - enable only at -O3 or similar. | |
| // if (ENABLE_UNSAFE_OPTS && argCount == 2 && argTypes[0].name == "void" && !isClassMethodFunc) { | |
| // return FUNCTION_TABLE[fn]; | |
| // } | |
| // Determine if we need to use a dynamic stack to store the destructors for the function parameters. | |
| // TODO: Remove this completely once all function invokers are being dynamically generated. | |
| var needsDestructorStack = usesDestructorStack(argTypes); | |
| var returns = !argTypes[0].isVoid; | |
| var expectedArgCount = argCount - 2; | |
| #if ASSERTIONS | |
| var minArgs = getRequiredArgCount(argTypes); | |
| #endif | |
| #if DYNAMIC_EXECUTION == 0 && !EMBIND_AOT | |
| var argsWired = new Array(expectedArgCount); | |
| var invokerFuncArgs = []; | |
| var destructors = []; | |
| var invokerFn = function(...args) { | |
| #if ASSERTIONS | |
| checkArgCount(args.length, minArgs, expectedArgCount, humanName, throwBindingError); | |
| #endif | |
| #if EMSCRIPTEN_TRACING | |
| Module.emscripten_trace_enter_context(`embind::${humanName}`); | |
| #endif | |
| destructors.length = 0; | |
| var thisWired; | |
| invokerFuncArgs.length = isClassMethodFunc ? 2 : 1; | |
| invokerFuncArgs[0] = cppTargetFunc; | |
| if (isClassMethodFunc) { | |
| thisWired = argTypes[1].toWireType(destructors, this); | |
| invokerFuncArgs[1] = thisWired; | |
| } | |
| for (var i = 0; i < expectedArgCount; ++i) { | |
| argsWired[i] = argTypes[i + 2].toWireType(destructors, args[i]); | |
| invokerFuncArgs.push(argsWired[i]); | |
| } | |
| var rv = cppInvokerFunc(...invokerFuncArgs); | |
| function onDone(rv) { | |
| if (needsDestructorStack) { | |
| runDestructors(destructors); | |
| } else { | |
| for (var i = isClassMethodFunc ? 1 : 2; i < argTypes.length; i++) { | |
| var param = i === 1 ? thisWired : argsWired[i - 2]; | |
| if (argTypes[i].destructorFunction !== null) { | |
| argTypes[i].destructorFunction(param); | |
| } | |
| } | |
| } | |
| #if EMSCRIPTEN_TRACING | |
| Module.emscripten_trace_exit_context(); | |
| #endif | |
| if (returns) { | |
| return argTypes[0].fromWireType(rv); | |
| } | |
| } | |
| #if ASYNCIFY == 1 | |
| if (Asyncify.currData) { | |
| return Asyncify.whenDone().then(onDone); | |
| } | |
| #elif ASYNCIFY == 2 | |
| if (isAsync) { | |
| return rv.then(onDone); | |
| } | |
| #endif | |
| return onDone(rv); | |
| }; | |
| #else | |
| // Build the arguments that will be passed into the closure around the invoker | |
| // function. | |
| var retType = argTypes[0]; | |
| var instType = argTypes[1]; | |
| var closureArgs = [humanName, throwBindingError, cppInvokerFunc, cppTargetFunc, runDestructors, retType.fromWireType.bind(retType), instType?.toWireType.bind(instType)]; | |
| #if EMSCRIPTEN_TRACING | |
| closureArgs.push(Module); | |
| #endif | |
| for (var i = 2; i < argCount; ++i) { | |
| var argType = argTypes[i]; | |
| closureArgs.push(argType.toWireType.bind(argType)); | |
| } | |
| #if ASYNCIFY == 1 | |
| closureArgs.push(Asyncify); | |
| #endif | |
| if (!needsDestructorStack) { | |
| // Skip return value at index 0 - it's not deleted here. Also skip class type if not a method. | |
| for (var i = isClassMethodFunc?1:2; i < argTypes.length; ++i) { | |
| if (argTypes[i].destructorFunction !== null) { | |
| closureArgs.push(argTypes[i].destructorFunction); | |
| } | |
| } | |
| } | |
| #if ASSERTIONS | |
| closureArgs.push(checkArgCount, minArgs, expectedArgCount); | |
| #endif | |
| #if EMBIND_AOT | |
| var signature = createJsInvokerSignature(argTypes, isClassMethodFunc, returns, isAsync); | |
| var invokerFn = InvokerFunctions[signature](...closureArgs); | |
| #else | |
| let invokerFactory = createJsInvoker(argTypes, isClassMethodFunc, returns, isAsync); | |
| var invokerFn = invokerFactory(...closureArgs); | |
| #endif | |
| #endif | |
| return createNamedFunction(humanName, invokerFn); | |
| }, | |
| $embind__requireFunction__deps: ['$AsciiToString', '$throwBindingError' | |
| #if DYNCALLS || !WASM_BIGINT || MEMORY64 || CAN_ADDRESS_2GB | |
| , '$getDynCaller' | |
| #endif | |
| ], | |
| $embind__requireFunction: (signature, rawFunction, isAsync = false) => { | |
| #if ASSERTIONS && ASYNCIFY != 2 | |
| assert(!isAsync, 'async bindings are only supported with JSPI'); | |
| #endif | |
| signature = AsciiToString(signature); | |
| function makeDynCaller() { | |
| #if DYNCALLS | |
| return getDynCaller(signature, rawFunction); | |
| #else | |
| #if !WASM_BIGINT | |
| if (signature.includes('j')) { | |
| return getDynCaller(signature, rawFunction); | |
| } | |
| #endif | |
| #if MEMORY64 || CAN_ADDRESS_2GB | |
| if (signature.includes('p')) { | |
| return getDynCaller(signature, rawFunction, isAsync); | |
| } | |
| #endif | |
| var rtn = getWasmTableEntry(rawFunction); | |
| #if JSPI | |
| if (isAsync) { | |
| rtn = WebAssembly.promising(rtn); | |
| } | |
| #endif | |
| return rtn; | |
| #endif | |
| } | |
| var fp = makeDynCaller(); | |
| if (typeof fp != 'function') { | |
| throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`); | |
| } | |
| return fp; | |
| }, | |
| _embind_register_function__deps: [ | |
| '$craftInvokerFunction', '$exposePublicSymbol', '$heap32VectorToArray', | |
| '$AsciiToString', '$replacePublicSymbol', '$embind__requireFunction', | |
| '$throwUnboundTypeError', '$whenDependentTypesAreResolved', '$getFunctionName'], | |
| _embind_register_function: (name, argCount, rawArgTypesAddr, signature, rawInvoker, fn, isAsync, isNonnullReturn) => { | |
| var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); | |
| name = AsciiToString(name); | |
| name = getFunctionName(name); | |
| rawInvoker = embind__requireFunction(signature, rawInvoker, isAsync); | |
| exposePublicSymbol(name, function() { | |
| throwUnboundTypeError(`Cannot call ${name} due to unbound types`, argTypes); | |
| }, argCount - 1); | |
| whenDependentTypesAreResolved([], argTypes, (argTypes) => { | |
| var invokerArgsArray = [argTypes[0] /* return value */, null /* no class 'this'*/].concat(argTypes.slice(1) /* actual params */); | |
| replacePublicSymbol(name, craftInvokerFunction(name, invokerArgsArray, null /* no class 'this'*/, rawInvoker, fn, isAsync), argCount - 1); | |
| return []; | |
| }); | |
| }, | |
| _embind_register_value_array__deps: [ | |
| '$tupleRegistrations', '$AsciiToString', '$embind__requireFunction'], | |
| _embind_register_value_array: ( | |
| rawType, | |
| name, | |
| constructorSignature, | |
| rawConstructor, | |
| destructorSignature, | |
| rawDestructor | |
| ) => { | |
| tupleRegistrations[rawType] = { | |
| name: AsciiToString(name), | |
| rawConstructor: embind__requireFunction(constructorSignature, rawConstructor), | |
| rawDestructor: embind__requireFunction(destructorSignature, rawDestructor), | |
| elements: [], | |
| }; | |
| }, | |
| _embind_register_value_array_element__deps: [ | |
| '$tupleRegistrations', '$embind__requireFunction'], | |
| _embind_register_value_array_element: ( | |
| rawTupleType, | |
| getterReturnType, | |
| getterSignature, | |
| getter, | |
| getterContext, | |
| setterArgumentType, | |
| setterSignature, | |
| setter, | |
| setterContext | |
| ) => { | |
| tupleRegistrations[rawTupleType].elements.push({ | |
| getterReturnType, | |
| getter: embind__requireFunction(getterSignature, getter), | |
| getterContext, | |
| setterArgumentType, | |
| setter: embind__requireFunction(setterSignature, setter), | |
| setterContext, | |
| }); | |
| }, | |
| _embind_finalize_value_array__deps: [ | |
| '$tupleRegistrations', '$runDestructors', | |
| '$readPointer', '$whenDependentTypesAreResolved'], | |
| _embind_finalize_value_array: (rawTupleType) => { | |
| var reg = tupleRegistrations[rawTupleType]; | |
| delete tupleRegistrations[rawTupleType]; | |
| var elements = reg.elements; | |
| var elementsLength = elements.length; | |
| var elementTypes = elements.map((elt) => elt.getterReturnType). | |
| concat(elements.map((elt) => elt.setterArgumentType)); | |
| var rawConstructor = reg.rawConstructor; | |
| var rawDestructor = reg.rawDestructor; | |
| whenDependentTypesAreResolved([rawTupleType], elementTypes, (elementTypes) => { | |
| for (const [i, elt] of elements.entries()) { | |
| const getterReturnType = elementTypes[i]; | |
| const getter = elt.getter; | |
| const getterContext = elt.getterContext; | |
| const setterArgumentType = elementTypes[i + elementsLength]; | |
| const setter = elt.setter; | |
| const setterContext = elt.setterContext; | |
| elt.read = (ptr) => getterReturnType.fromWireType(getter(getterContext, ptr)); | |
| elt.write = (ptr, o) => { | |
| var destructors = []; | |
| setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o)); | |
| runDestructors(destructors); | |
| }; | |
| } | |
| return [{ | |
| name: reg.name, | |
| fromWireType: (ptr) => { | |
| var rv = new Array(elementsLength); | |
| for (var i = 0; i < elementsLength; ++i) { | |
| rv[i] = elements[i].read(ptr); | |
| } | |
| rawDestructor(ptr); | |
| return rv; | |
| }, | |
| toWireType: (destructors, o) => { | |
| if (elementsLength !== o.length) { | |
| throw new TypeError(`Incorrect number of tuple elements for ${reg.name}: expected=${elementsLength}, actual=${o.length}`); | |
| } | |
| var ptr = rawConstructor(); | |
| for (var i = 0; i < elementsLength; ++i) { | |
| elements[i].write(ptr, o[i]); | |
| } | |
| if (destructors !== null) { | |
| destructors.push(rawDestructor, ptr); | |
| } | |
| return ptr; | |
| }, | |
| readValueFromPointer: readPointer, | |
| destructorFunction: rawDestructor, | |
| }]; | |
| }); | |
| }, | |
| _embind_register_value_object__deps: [ | |
| '$structRegistrations', '$AsciiToString', '$embind__requireFunction'], | |
| _embind_register_value_object: ( | |
| rawType, | |
| name, | |
| constructorSignature, | |
| rawConstructor, | |
| destructorSignature, | |
| rawDestructor | |
| ) => { | |
| structRegistrations[rawType] = { | |
| name: AsciiToString(name), | |
| rawConstructor: embind__requireFunction(constructorSignature, rawConstructor), | |
| rawDestructor: embind__requireFunction(destructorSignature, rawDestructor), | |
| fields: [], | |
| }; | |
| }, | |
| _embind_register_value_object_field__deps: [ | |
| '$structRegistrations', '$AsciiToString', '$embind__requireFunction'], | |
| _embind_register_value_object_field: ( | |
| structType, | |
| fieldName, | |
| getterReturnType, | |
| getterSignature, | |
| getter, | |
| getterContext, | |
| setterArgumentType, | |
| setterSignature, | |
| setter, | |
| setterContext | |
| ) => { | |
| structRegistrations[structType].fields.push({ | |
| fieldName: AsciiToString(fieldName), | |
| getterReturnType, | |
| getter: embind__requireFunction(getterSignature, getter), | |
| getterContext, | |
| setterArgumentType, | |
| setter: embind__requireFunction(setterSignature, setter), | |
| setterContext, | |
| }); | |
| }, | |
| _embind_finalize_value_object__deps: [ | |
| '$structRegistrations', '$runDestructors', | |
| '$readPointer', '$whenDependentTypesAreResolved'], | |
| _embind_finalize_value_object: (structType) => { | |
| var reg = structRegistrations[structType]; | |
| delete structRegistrations[structType]; | |
| var rawConstructor = reg.rawConstructor; | |
| var rawDestructor = reg.rawDestructor; | |
| var fieldRecords = reg.fields; | |
| var fieldTypes = fieldRecords.map((field) => field.getterReturnType). | |
| concat(fieldRecords.map((field) => field.setterArgumentType)); | |
| whenDependentTypesAreResolved([structType], fieldTypes, (fieldTypes) => { | |
| var fields = {}; | |
| for (var [i, field] of fieldRecords.entries()) { | |
| const getterReturnType = fieldTypes[i]; | |
| const getter = field.getter; | |
| const getterContext = field.getterContext; | |
| const setterArgumentType = fieldTypes[i + fieldRecords.length]; | |
| const setter = field.setter; | |
| const setterContext = field.setterContext; | |
| fields[field.fieldName] = { | |
| read: (ptr) => getterReturnType.fromWireType(getter(getterContext, ptr)), | |
| write: (ptr, o) => { | |
| var destructors = []; | |
| setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o)); | |
| runDestructors(destructors); | |
| }, | |
| optional: getterReturnType.optional, | |
| }; | |
| } | |
| return [{ | |
| name: reg.name, | |
| fromWireType: (ptr) => { | |
| var rv = {}; | |
| for (var i in fields) { | |
| rv[i] = fields[i].read(ptr); | |
| } | |
| rawDestructor(ptr); | |
| return rv; | |
| }, | |
| toWireType: (destructors, o) => { | |
| // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: | |
| // assume all fields are present without checking. | |
| for (var fieldName in fields) { | |
| if (!(fieldName in o) && !fields[fieldName].optional) { | |
| throw new TypeError(`Missing field: "${fieldName}"`); | |
| } | |
| } | |
| var ptr = rawConstructor(); | |
| for (fieldName in fields) { | |
| fields[fieldName].write(ptr, o[fieldName]); | |
| } | |
| if (destructors !== null) { | |
| destructors.push(rawDestructor, ptr); | |
| } | |
| return ptr; | |
| }, | |
| readValueFromPointer: readPointer, | |
| destructorFunction: rawDestructor, | |
| }]; | |
| }); | |
| }, | |
| $genericPointerToWireType__docs: '/** @suppress {globalThis} */', | |
| $genericPointerToWireType__deps: ['$throwBindingError', '$upcastPointer'], | |
| $genericPointerToWireType: function(destructors, handle) { | |
| var ptr; | |
| if (handle === null) { | |
| if (this.isReference) { | |
| throwBindingError(`null is not a valid ${this.name}`); | |
| } | |
| if (this.isSmartPointer) { | |
| ptr = this.rawConstructor(); | |
| if (destructors !== null) { | |
| destructors.push(this.rawDestructor, ptr); | |
| } | |
| return ptr; | |
| } else { | |
| return 0; | |
| } | |
| } | |
| if (!handle || !handle.$$) { | |
| throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); | |
| } | |
| if (!handle.$$.ptr) { | |
| throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`); | |
| } | |
| if (!this.isConst && handle.$$.ptrType.isConst) { | |
| throwBindingError(`Cannot convert argument of type ${(handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name)} to parameter type ${this.name}`); | |
| } | |
| var handleClass = handle.$$.ptrType.registeredClass; | |
| ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); | |
| if (this.isSmartPointer) { | |
| // TODO: this is not strictly true | |
| // We could support BY_EMVAL conversions from raw pointers to smart pointers | |
| // because the smart pointer can hold a reference to the handle | |
| if (undefined === handle.$$.smartPtr) { | |
| throwBindingError('Passing raw pointer to smart pointer is illegal'); | |
| } | |
| switch (this.sharingPolicy) { | |
| case 0: // NONE | |
| // no upcasting | |
| if (handle.$$.smartPtrType === this) { | |
| ptr = handle.$$.smartPtr; | |
| } else { | |
| throwBindingError(`Cannot convert argument of type ${(handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name)} to parameter type ${this.name}`); | |
| } | |
| break; | |
| case 1: // INTRUSIVE | |
| ptr = handle.$$.smartPtr; | |
| break; | |
| case 2: // BY_EMVAL | |
| if (handle.$$.smartPtrType === this) { | |
| ptr = handle.$$.smartPtr; | |
| } else { | |
| var clonedHandle = handle['clone'](); | |
| ptr = this.rawShare( | |
| ptr, | |
| Emval.toHandle(() => clonedHandle['delete']()) | |
| ); | |
| if (destructors !== null) { | |
| destructors.push(this.rawDestructor, ptr); | |
| } | |
| } | |
| break; | |
| default: | |
| throwBindingError('Unsupported sharing policy'); | |
| } | |
| } | |
| return ptr; | |
| }, | |
| $constNoSmartPtrRawPointerToWireType__docs: '/** @suppress {globalThis} */', | |
| // If we know a pointer type is not going to have SmartPtr logic in it, we can | |
| // special-case optimize it a bit (compare to genericPointerToWireType) | |
| $constNoSmartPtrRawPointerToWireType__deps: ['$throwBindingError', '$upcastPointer', '$embindRepr'], | |
| $constNoSmartPtrRawPointerToWireType: function(destructors, handle) { | |
| if (handle === null) { | |
| if (this.isReference) { | |
| throwBindingError(`null is not a valid ${this.name}`); | |
| } | |
| return 0; | |
| } | |
| if (!handle.$$) { | |
| throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); | |
| } | |
| if (!handle.$$.ptr) { | |
| throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`); | |
| } | |
| var handleClass = handle.$$.ptrType.registeredClass; | |
| var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); | |
| return ptr; | |
| }, | |
| $nonConstNoSmartPtrRawPointerToWireType__docs: '/** @suppress {globalThis} */', | |
| // An optimized version for non-const method accesses - there we must additionally restrict that | |
| // the pointer is not a const-pointer. | |
| $nonConstNoSmartPtrRawPointerToWireType__deps: ['$throwBindingError', '$upcastPointer', '$embindRepr'], | |
| $nonConstNoSmartPtrRawPointerToWireType: function(destructors, handle) { | |
| if (handle === null) { | |
| if (this.isReference) { | |
| throwBindingError(`null is not a valid ${this.name}`); | |
| } | |
| return 0; | |
| } | |
| if (!handle.$$) { | |
| throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); | |
| } | |
| if (!handle.$$.ptr) { | |
| throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`); | |
| } | |
| if (handle.$$.ptrType.isConst) { | |
| throwBindingError(`Cannot convert argument of type ${handle.$$.ptrType.name} to parameter type ${this.name}`); | |
| } | |
| var handleClass = handle.$$.ptrType.registeredClass; | |
| var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); | |
| return ptr; | |
| }, | |
| $init_RegisteredPointer__deps: [ | |
| '$RegisteredPointer', | |
| '$readPointer', | |
| '$RegisteredPointer_fromWireType', | |
| ], | |
| $init_RegisteredPointer: () => { | |
| Object.assign(RegisteredPointer.prototype, { | |
| getPointee(ptr) { | |
| if (this.rawGetPointee) { | |
| ptr = this.rawGetPointee(ptr); | |
| } | |
| return ptr; | |
| }, | |
| destructor(ptr) { | |
| this.rawDestructor?.(ptr); | |
| }, | |
| readValueFromPointer: readPointer, | |
| fromWireType: RegisteredPointer_fromWireType, | |
| }); | |
| }, | |
| $RegisteredPointer__docs: `/** @constructor | |
| @param {*=} pointeeType, | |
| @param {*=} sharingPolicy, | |
| @param {*=} rawGetPointee, | |
| @param {*=} rawConstructor, | |
| @param {*=} rawShare, | |
| @param {*=} rawDestructor, | |
| */`, | |
| $RegisteredPointer__deps: [ | |
| '$constNoSmartPtrRawPointerToWireType', '$genericPointerToWireType', | |
| '$nonConstNoSmartPtrRawPointerToWireType', '$init_RegisteredPointer'], | |
| $RegisteredPointer__postset: 'init_RegisteredPointer()', | |
| $RegisteredPointer: function( | |
| name, | |
| registeredClass, | |
| isReference, | |
| isConst, | |
| // smart pointer properties | |
| isSmartPointer, | |
| pointeeType, | |
| sharingPolicy, | |
| rawGetPointee, | |
| rawConstructor, | |
| rawShare, | |
| rawDestructor | |
| ) { | |
| this.name = name; | |
| this.registeredClass = registeredClass; | |
| this.isReference = isReference; | |
| this.isConst = isConst; | |
| // smart pointer properties | |
| this.isSmartPointer = isSmartPointer; | |
| this.pointeeType = pointeeType; | |
| this.sharingPolicy = sharingPolicy; | |
| this.rawGetPointee = rawGetPointee; | |
| this.rawConstructor = rawConstructor; | |
| this.rawShare = rawShare; | |
| this.rawDestructor = rawDestructor; | |
| if (!isSmartPointer && registeredClass.baseClass === undefined) { | |
| if (isConst) { | |
| this.toWireType = constNoSmartPtrRawPointerToWireType; | |
| this.destructorFunction = null; | |
| } else { | |
| this.toWireType = nonConstNoSmartPtrRawPointerToWireType; | |
| this.destructorFunction = null; | |
| } | |
| } else { | |
| this.toWireType = genericPointerToWireType; | |
| // Here we must leave this.destructorFunction undefined, since whether genericPointerToWireType returns | |
| // a pointer that needs to be freed up is runtime-dependent, and cannot be evaluated at registration time. | |
| // TODO: Create an alternative mechanism that allows removing the use of var destructors = []; array in | |
| // craftInvokerFunction altogether. | |
| } | |
| }, | |
| $RegisteredPointer_fromWireType__docs: '/** @suppress {globalThis} */', | |
| $RegisteredPointer_fromWireType__deps: [ | |
| '$downcastPointer', '$registeredPointers', | |
| '$getInheritedInstance', '$makeClassHandle', | |
| #if MEMORY64 | |
| '$bigintToI53Checked' | |
| #endif | |
| ], | |
| $RegisteredPointer_fromWireType: function(ptr) { | |
| // ptr is a raw pointer (or a raw smartpointer) | |
| #if MEMORY64 | |
| ptr = bigintToI53Checked(ptr); | |
| #if ASSERTIONS | |
| assert(Number.isSafeInteger(ptr)); | |
| #endif | |
| #endif | |
| // rawPointer is a maybe-null raw pointer | |
| var rawPointer = this.getPointee(ptr); | |
| if (!rawPointer) { | |
| this.destructor(ptr); | |
| return null; | |
| } | |
| var registeredInstance = getInheritedInstance(this.registeredClass, rawPointer); | |
| if (undefined !== registeredInstance) { | |
| // JS object has been neutered, time to repopulate it | |
| if (0 === registeredInstance.$$.count.value) { | |
| registeredInstance.$$.ptr = rawPointer; | |
| registeredInstance.$$.smartPtr = ptr; | |
| return registeredInstance['clone'](); | |
| } else { | |
| // else, just increment reference count on existing object | |
| // it already has a reference to the smart pointer | |
| var rv = registeredInstance['clone'](); | |
| this.destructor(ptr); | |
| return rv; | |
| } | |
| } | |
| function makeDefaultHandle() { | |
| if (this.isSmartPointer) { | |
| return makeClassHandle(this.registeredClass.instancePrototype, { | |
| ptrType: this.pointeeType, | |
| ptr: rawPointer, | |
| smartPtrType: this, | |
| smartPtr: ptr, | |
| }); | |
| } else { | |
| return makeClassHandle(this.registeredClass.instancePrototype, { | |
| ptrType: this, | |
| ptr, | |
| }); | |
| } | |
| } | |
| var actualType = this.registeredClass.getActualType(rawPointer); | |
| var registeredPointerRecord = registeredPointers[actualType]; | |
| if (!registeredPointerRecord) { | |
| return makeDefaultHandle.call(this); | |
| } | |
| var toType; | |
| if (this.isConst) { | |
| toType = registeredPointerRecord.constPointerType; | |
| } else { | |
| toType = registeredPointerRecord.pointerType; | |
| } | |
| var dp = downcastPointer( | |
| rawPointer, | |
| this.registeredClass, | |
| toType.registeredClass); | |
| if (dp === null) { | |
| return makeDefaultHandle.call(this); | |
| } | |
| if (this.isSmartPointer) { | |
| return makeClassHandle(toType.registeredClass.instancePrototype, { | |
| ptrType: toType, | |
| ptr: dp, | |
| smartPtrType: this, | |
| smartPtr: ptr, | |
| }); | |
| } else { | |
| return makeClassHandle(toType.registeredClass.instancePrototype, { | |
| ptrType: toType, | |
| ptr: dp, | |
| }); | |
| } | |
| }, | |
| $runDestructor: ($$) => { | |
| if ($$.smartPtr) { | |
| $$.smartPtrType.rawDestructor($$.smartPtr); | |
| } else { | |
| $$.ptrType.registeredClass.rawDestructor($$.ptr); | |
| } | |
| }, | |
| $releaseClassHandle__deps: ['$runDestructor'], | |
| $releaseClassHandle: ($$) => { | |
| $$.count.value -= 1; | |
| var toDelete = 0 === $$.count.value; | |
| if (toDelete) { | |
| runDestructor($$); | |
| } | |
| }, | |
| $finalizationRegistry: false, | |
| $detachFinalizer_deps: ['$finalizationRegistry'], | |
| $detachFinalizer: (handle) => {}, | |
| $attachFinalizer__deps: [ | |
| '$finalizationRegistry', '$detachFinalizer', '$releaseClassHandle', | |
| #if ASSERTIONS | |
| '$RegisteredPointer_fromWireType' | |
| #endif | |
| ], | |
| $attachFinalizer: (handle) => { | |
| if (!globalThis.FinalizationRegistry) { | |
| attachFinalizer = (handle) => handle; | |
| return handle; | |
| } | |
| // If the running environment has a FinalizationRegistry (see | |
| // https://github.com/tc39/proposal-weakrefs), then attach finalizers | |
| // for class handles. We check for the presence of FinalizationRegistry | |
| // at run-time, not build-time. | |
| finalizationRegistry = new FinalizationRegistry((info) => { | |
| #if ASSERTIONS | |
| console.warn(info.leakWarning); | |
| #endif | |
| releaseClassHandle(info.$$); | |
| }); | |
| attachFinalizer = (handle) => { | |
| var $$ = handle.$$; | |
| var hasSmartPtr = !!$$.smartPtr; | |
| if (hasSmartPtr) { | |
| // We should not call the destructor on raw pointers in case other code expects the pointee to live | |
| var info = { $$: $$ }; | |
| #if ASSERTIONS | |
| // Create a warning as an Error instance in advance so that we can store | |
| // the current stacktrace and point to it when / if a leak is detected. | |
| // This is more useful than the empty stacktrace of `FinalizationRegistry` | |
| // callback. | |
| var cls = $$.ptrType.registeredClass; | |
| var err = new Error(`Embind found a leaked C++ instance ${cls.name} <${ptrToString($$.ptr)}>.\n` + | |
| "We'll free it automatically in this case, but this functionality is not reliable across various environments.\n" + | |
| "Make sure to invoke .delete() manually once you're done with the instance instead.\n" + | |
| "Originally allocated"); // `.stack` will add "at ..." after this sentence | |
| if ('captureStackTrace' in Error) { | |
| Error.captureStackTrace(err, RegisteredPointer_fromWireType); | |
| } | |
| info.leakWarning = err.stack.replace(/^Error: /, ''); | |
| #endif | |
| finalizationRegistry.register(handle, info, handle); | |
| } | |
| return handle; | |
| }; | |
| detachFinalizer = (handle) => finalizationRegistry.unregister(handle); | |
| return attachFinalizer(handle); | |
| }, | |
| $makeClassHandle__deps: ['$throwInternalError', '$attachFinalizer'], | |
| $makeClassHandle: (prototype, record) => { | |
| if (!record.ptrType || !record.ptr) { | |
| throwInternalError('makeClassHandle requires ptr and ptrType'); | |
| } | |
| var hasSmartPtrType = !!record.smartPtrType; | |
| var hasSmartPtr = !!record.smartPtr; | |
| if (hasSmartPtrType !== hasSmartPtr) { | |
| throwInternalError('Both smartPtrType and smartPtr must be specified'); | |
| } | |
| record.count = { value: 1 }; | |
| return attachFinalizer(Object.create(prototype, { | |
| $$: { | |
| value: record, | |
| writable: true, | |
| }, | |
| })); | |
| }, | |
| $init_ClassHandle__deps: [ | |
| '$ClassHandle', | |
| '$shallowCopyInternalPointer', | |
| '$throwInstanceAlreadyDeleted', | |
| '$attachFinalizer', | |
| '$releaseClassHandle', | |
| '$throwBindingError', | |
| '$detachFinalizer', | |
| '$flushPendingDeletes', | |
| '$delayFunction', | |
| ], | |
| $init_ClassHandle: () => { | |
| let proto = ClassHandle.prototype; | |
| Object.assign(proto, { | |
| "isAliasOf"(other) { | |
| if (!(this instanceof ClassHandle)) { | |
| return false; | |
| } | |
| if (!(other instanceof ClassHandle)) { | |
| return false; | |
| } | |
| var leftClass = this.$$.ptrType.registeredClass; | |
| var left = this.$$.ptr; | |
| other.$$ = /** @type {Object} */ (other.$$); | |
| var rightClass = other.$$.ptrType.registeredClass; | |
| var right = other.$$.ptr; | |
| while (leftClass.baseClass) { | |
| left = leftClass.upcast(left); | |
| leftClass = leftClass.baseClass; | |
| } | |
| while (rightClass.baseClass) { | |
| right = rightClass.upcast(right); | |
| rightClass = rightClass.baseClass; | |
| } | |
| return leftClass === rightClass && left === right; | |
| }, | |
| "clone"() { | |
| if (!this.$$.ptr) { | |
| throwInstanceAlreadyDeleted(this); | |
| } | |
| if (this.$$.preservePointerOnDelete) { | |
| this.$$.count.value += 1; | |
| return this; | |
| } else { | |
| var clone = attachFinalizer(Object.create(Object.getPrototypeOf(this), { | |
| $$: { | |
| value: shallowCopyInternalPointer(this.$$), | |
| } | |
| })); | |
| clone.$$.count.value += 1; | |
| clone.$$.deleteScheduled = false; | |
| return clone; | |
| } | |
| }, | |
| "delete"() { | |
| if (!this.$$.ptr) { | |
| throwInstanceAlreadyDeleted(this); | |
| } | |
| if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { | |
| throwBindingError('Object already scheduled for deletion'); | |
| } | |
| detachFinalizer(this); | |
| releaseClassHandle(this.$$); | |
| if (!this.$$.preservePointerOnDelete) { | |
| this.$$.smartPtr = undefined; | |
| this.$$.ptr = undefined; | |
| } | |
| }, | |
| "isDeleted"() { | |
| return !this.$$.ptr; | |
| }, | |
| "deleteLater"() { | |
| if (!this.$$.ptr) { | |
| throwInstanceAlreadyDeleted(this); | |
| } | |
| if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { | |
| throwBindingError('Object already scheduled for deletion'); | |
| } | |
| deletionQueue.push(this); | |
| if (deletionQueue.length === 1 && delayFunction) { | |
| delayFunction(flushPendingDeletes); | |
| } | |
| this.$$.deleteScheduled = true; | |
| return this; | |
| }, | |
| }); | |
| // Support `using ...` from https://github.com/tc39/proposal-explicit-resource-management. | |
| const symbolDispose = Symbol.dispose; | |
| if (symbolDispose) { | |
| proto[symbolDispose] = proto['delete']; | |
| } | |
| }, | |
| $ClassHandle__docs: '/** @constructor */', | |
| $ClassHandle__deps: ['$init_ClassHandle'], | |
| $ClassHandle__postset: 'init_ClassHandle()', | |
| // root of all pointer and smart pointer handles in embind | |
| $ClassHandle: function() { | |
| }, | |
| $throwInstanceAlreadyDeleted__deps: ['$throwBindingError'], | |
| $throwInstanceAlreadyDeleted: (obj) => { | |
| function getInstanceTypeName(handle) { | |
| return handle.$$.ptrType.registeredClass.name; | |
| } | |
| throwBindingError(getInstanceTypeName(obj) + ' instance already deleted'); | |
| }, | |
| $deletionQueue: [], | |
| $flushPendingDeletes__deps: ['$deletionQueue'], | |
| $flushPendingDeletes: () => { | |
| while (deletionQueue.length) { | |
| var obj = deletionQueue.pop(); | |
| obj.$$.deleteScheduled = false; | |
| obj['delete'](); | |
| } | |
| }, | |
| $delayFunction: undefined, | |
| $setDelayFunction__deps: ['$delayFunction', '$deletionQueue', '$flushPendingDeletes'], | |
| $setDelayFunction: (fn) => { | |
| delayFunction = fn; | |
| if (deletionQueue.length && delayFunction) { | |
| delayFunction(flushPendingDeletes); | |
| } | |
| }, | |
| $RegisteredClass__docs: '/** @constructor */', | |
| $RegisteredClass: function(name, | |
| constructor, | |
| instancePrototype, | |
| rawDestructor, | |
| baseClass, | |
| getActualType, | |
| upcast, | |
| downcast) { | |
| this.name = name; | |
| this.constructor = constructor; | |
| this.instancePrototype = instancePrototype; | |
| this.rawDestructor = rawDestructor; | |
| this.baseClass = baseClass; | |
| this.getActualType = getActualType; | |
| this.upcast = upcast; | |
| this.downcast = downcast; | |
| this.pureVirtualFunctions = []; | |
| }, | |
| $shallowCopyInternalPointer: (o) => { | |
| return { | |
| count: o.count, | |
| deleteScheduled: o.deleteScheduled, | |
| preservePointerOnDelete: o.preservePointerOnDelete, | |
| ptr: o.ptr, | |
| ptrType: o.ptrType, | |
| smartPtr: o.smartPtr, | |
| smartPtrType: o.smartPtrType, | |
| }; | |
| }, | |
| _embind_register_class__deps: [ | |
| '$BindingError', '$ClassHandle', '$createNamedFunction', | |
| '$registeredPointers', '$exposePublicSymbol', | |
| '$makeLegalFunctionName', '$AsciiToString', | |
| '$RegisteredClass', '$RegisteredPointer', '$replacePublicSymbol', | |
| '$embind__requireFunction', '$throwUnboundTypeError', | |
| '$whenDependentTypesAreResolved'], | |
| _embind_register_class: (rawType, | |
| rawPointerType, | |
| rawConstPointerType, | |
| baseClassRawType, | |
| getActualTypeSignature, | |
| getActualType, | |
| upcastSignature, | |
| upcast, | |
| downcastSignature, | |
| downcast, | |
| name, | |
| destructorSignature, | |
| rawDestructor) => { | |
| name = AsciiToString(name); | |
| getActualType = embind__requireFunction(getActualTypeSignature, getActualType); | |
| upcast &&= embind__requireFunction(upcastSignature, upcast); | |
| downcast &&= embind__requireFunction(downcastSignature, downcast); | |
| rawDestructor = embind__requireFunction(destructorSignature, rawDestructor); | |
| var legalFunctionName = makeLegalFunctionName(name); | |
| exposePublicSymbol(legalFunctionName, function() { | |
| // this code cannot run if baseClassRawType is zero | |
| throwUnboundTypeError(`Cannot construct ${name} due to unbound types`, [baseClassRawType]); | |
| }); | |
| whenDependentTypesAreResolved( | |
| [rawType, rawPointerType, rawConstPointerType], | |
| baseClassRawType ? [baseClassRawType] : [], | |
| (base) => { | |
| base = base[0]; | |
| var baseClass; | |
| var basePrototype; | |
| if (baseClassRawType) { | |
| baseClass = base.registeredClass; | |
| basePrototype = baseClass.instancePrototype; | |
| } else { | |
| basePrototype = ClassHandle.prototype; | |
| } | |
| var constructor = createNamedFunction(name, function(...args) { | |
| if (Object.getPrototypeOf(this) !== instancePrototype) { | |
| throw new BindingError(`Use 'new' to construct ${name}`); | |
| } | |
| if (undefined === registeredClass.constructor_body) { | |
| throw new BindingError(`${name} has no accessible constructor`); | |
| } | |
| var body = registeredClass.constructor_body[args.length]; | |
| if (undefined === body) { | |
| throw new BindingError(`Tried to invoke ctor of ${name} with invalid number of parameters (${args.length}) - expected (${Object.keys(registeredClass.constructor_body).toString()}) parameters instead!`); | |
| } | |
| return body.apply(this, args); | |
| }); | |
| var instancePrototype = Object.create(basePrototype, { | |
| constructor: { value: constructor }, | |
| }); | |
| constructor.prototype = instancePrototype; | |
| var registeredClass = new RegisteredClass(name, | |
| constructor, | |
| instancePrototype, | |
| rawDestructor, | |
| baseClass, | |
| getActualType, | |
| upcast, | |
| downcast); | |
| if (registeredClass.baseClass) { | |
| // Keep track of class hierarchy. Used to allow sub-classes to inherit class functions. | |
| registeredClass.baseClass.__derivedClasses ??= []; | |
| registeredClass.baseClass.__derivedClasses.push(registeredClass); | |
| } | |
| var referenceConverter = new RegisteredPointer(name, | |
| registeredClass, | |
| true, | |
| false, | |
| false); | |
| var pointerConverter = new RegisteredPointer(name + '*', | |
| registeredClass, | |
| false, | |
| false, | |
| false); | |
| var constPointerConverter = new RegisteredPointer(name + ' const*', | |
| registeredClass, | |
| false, | |
| true, | |
| false); | |
| registeredPointers[rawType] = { | |
| pointerType: pointerConverter, | |
| constPointerType: constPointerConverter | |
| }; | |
| replacePublicSymbol(legalFunctionName, constructor); | |
| return [referenceConverter, pointerConverter, constPointerConverter]; | |
| } | |
| ); | |
| }, | |
| _embind_register_iterable__deps: [ | |
| '$whenDependentTypesAreResolved', '$installIndexedIterator', '$AsciiToString', | |
| ], | |
| _embind_register_iterable: (rawClassType, rawElementType, sizeMethodName, getMethodName) => { | |
| sizeMethodName = AsciiToString(sizeMethodName); | |
| getMethodName = AsciiToString(getMethodName); | |
| whenDependentTypesAreResolved([], [rawClassType, rawElementType], (types) => { | |
| const classType = types[0]; | |
| installIndexedIterator(classType.registeredClass.instancePrototype, sizeMethodName, getMethodName); | |
| return []; | |
| }); | |
| }, | |
| _embind_register_class_constructor__deps: [ | |
| '$heap32VectorToArray', '$embind__requireFunction', | |
| '$whenDependentTypesAreResolved', | |
| '$craftInvokerFunction'], | |
| _embind_register_class_constructor: ( | |
| rawClassType, | |
| argCount, | |
| rawArgTypesAddr, | |
| invokerSignature, | |
| invoker, | |
| rawConstructor | |
| ) => { | |
| #if ASSERTIONS | |
| assert(argCount > 0); | |
| #endif | |
| var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); | |
| invoker = embind__requireFunction(invokerSignature, invoker); | |
| var args = [rawConstructor]; | |
| var destructors = []; | |
| whenDependentTypesAreResolved([], [rawClassType], (classType) => { | |
| classType = classType[0]; | |
| var humanName = `constructor ${classType.name}`; | |
| if (undefined === classType.registeredClass.constructor_body) { | |
| classType.registeredClass.constructor_body = []; | |
| } | |
| if (undefined !== classType.registeredClass.constructor_body[argCount - 1]) { | |
| throw new BindingError(`Cannot register multiple constructors with identical number of parameters (${argCount-1}) for class '${classType.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`); | |
| } | |
| classType.registeredClass.constructor_body[argCount - 1] = () => { | |
| throwUnboundTypeError(`Cannot construct ${classType.name} due to unbound types`, rawArgTypes); | |
| }; | |
| whenDependentTypesAreResolved([], rawArgTypes, (argTypes) => { | |
| // Insert empty slot for context type (argTypes[1]). | |
| argTypes.splice(1, 0, null); | |
| classType.registeredClass.constructor_body[argCount - 1] = craftInvokerFunction(humanName, argTypes, null, invoker, rawConstructor); | |
| return []; | |
| }); | |
| return []; | |
| }); | |
| }, | |
| $downcastPointer: (ptr, ptrClass, desiredClass) => { | |
| if (ptrClass === desiredClass) { | |
| return ptr; | |
| } | |
| if (undefined === desiredClass.baseClass) { | |
| return null; // no conversion | |
| } | |
| var rv = downcastPointer(ptr, ptrClass, desiredClass.baseClass); | |
| if (rv === null) { | |
| return null; | |
| } | |
| return desiredClass.downcast(rv); | |
| }, | |
| $upcastPointer__deps: ['$throwBindingError'], | |
| $upcastPointer: (ptr, ptrClass, desiredClass) => { | |
| while (ptrClass !== desiredClass) { | |
| if (!ptrClass.upcast) { | |
| throwBindingError(`Expected null or instance of ${desiredClass.name}, got an instance of ${ptrClass.name}`); | |
| } | |
| ptr = ptrClass.upcast(ptr); | |
| ptrClass = ptrClass.baseClass; | |
| } | |
| return ptr; | |
| }, | |
| $validateThis__deps: ['$throwBindingError', '$upcastPointer'], | |
| $validateThis: (this_, classType, humanName) => { | |
| if (!(this_ instanceof Object)) { | |
| throwBindingError(`${humanName} with invalid "this": ${this_}`); | |
| } | |
| if (!(this_ instanceof classType.registeredClass.constructor)) { | |
| throwBindingError(`${humanName} incompatible with "this" of type ${this_.constructor.name}`); | |
| } | |
| if (!this_.$$.ptr) { | |
| throwBindingError(`cannot call emscripten binding method ${humanName} on deleted object`); | |
| } | |
| // todo: kill this | |
| return upcastPointer(this_.$$.ptr, | |
| this_.$$.ptrType.registeredClass, | |
| classType.registeredClass); | |
| }, | |
| _embind_register_class_function__deps: [ | |
| '$craftInvokerFunction', '$heap32VectorToArray', '$AsciiToString', | |
| '$embind__requireFunction', '$throwUnboundTypeError', | |
| '$whenDependentTypesAreResolved', '$getFunctionName'], | |
| _embind_register_class_function: (rawClassType, | |
| methodName, | |
| argCount, | |
| rawArgTypesAddr, // [ReturnType, ThisType, Args...] | |
| invokerSignature, | |
| rawInvoker, | |
| context, | |
| isPureVirtual, | |
| isAsync, | |
| isNonnullReturn) => { | |
| var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); | |
| methodName = AsciiToString(methodName); | |
| methodName = getFunctionName(methodName); | |
| rawInvoker = embind__requireFunction(invokerSignature, rawInvoker, isAsync); | |
| whenDependentTypesAreResolved([], [rawClassType], (classType) => { | |
| classType = classType[0]; | |
| var humanName = `${classType.name}.${methodName}`; | |
| if (methodName.startsWith("@@")) { | |
| methodName = Symbol[methodName.substring(2)]; | |
| } | |
| if (isPureVirtual) { | |
| classType.registeredClass.pureVirtualFunctions.push(methodName); | |
| } | |
| function unboundTypesHandler() { | |
| throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`, rawArgTypes); | |
| } | |
| var proto = classType.registeredClass.instancePrototype; | |
| var method = proto[methodName]; | |
| if (undefined === method || (undefined === method.overloadTable && method.className !== classType.name && method.argCount === argCount - 2)) { | |
| // This is the first overload to be registered, OR we are replacing a | |
| // function in the base class with a function in the derived class. | |
| unboundTypesHandler.argCount = argCount - 2; | |
| unboundTypesHandler.className = classType.name; | |
| proto[methodName] = unboundTypesHandler; | |
| } else { | |
| // There was an existing function with the same name registered. Set up | |
| // a function overload routing table. | |
| ensureOverloadTable(proto, methodName, humanName); | |
| proto[methodName].overloadTable[argCount - 2] = unboundTypesHandler; | |
| } | |
| whenDependentTypesAreResolved([], rawArgTypes, (argTypes) => { | |
| var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context, isAsync); | |
| // Replace the initial unbound-handler-stub function with the | |
| // appropriate member function, now that all types are resolved. If | |
| // multiple overloads are registered for this function, the function | |
| // goes into an overload table. | |
| if (undefined === proto[methodName].overloadTable) { | |
| // Set argCount in case an overload is registered later | |
| memberFunction.argCount = argCount - 2; | |
| proto[methodName] = memberFunction; | |
| } else { | |
| proto[methodName].overloadTable[argCount - 2] = memberFunction; | |
| } | |
| return []; | |
| }); | |
| return []; | |
| }); | |
| }, | |
| _embind_register_class_property__deps: [ | |
| '$AsciiToString', '$embind__requireFunction', '$runDestructors', | |
| '$throwBindingError', '$throwUnboundTypeError', | |
| '$whenDependentTypesAreResolved', '$validateThis'], | |
| _embind_register_class_property: (classType, | |
| fieldName, | |
| getterReturnType, | |
| getterSignature, | |
| getter, | |
| getterContext, | |
| setterArgumentType, | |
| setterSignature, | |
| setter, | |
| setterContext) => { | |
| fieldName = AsciiToString(fieldName); | |
| getter = embind__requireFunction(getterSignature, getter); | |
| whenDependentTypesAreResolved([], [classType], (classType) => { | |
| classType = classType[0]; | |
| var humanName = `${classType.name}.${fieldName}`; | |
| var desc = { | |
| get() { | |
| throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [getterReturnType, setterArgumentType]); | |
| }, | |
| enumerable: true, | |
| configurable: true | |
| }; | |
| if (setter) { | |
| desc.set = () => throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [getterReturnType, setterArgumentType]); | |
| } else { | |
| desc.set = (v) => throwBindingError(humanName + ' is a read-only property'); | |
| } | |
| Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, desc); | |
| whenDependentTypesAreResolved( | |
| [], | |
| (setter ? [getterReturnType, setterArgumentType] : [getterReturnType]), | |
| (types) => { | |
| var getterReturnType = types[0]; | |
| var desc = { | |
| get() { | |
| var ptr = validateThis(this, classType, humanName + ' getter'); | |
| return getterReturnType.fromWireType(getter(getterContext, ptr)); | |
| }, | |
| enumerable: true | |
| }; | |
| if (setter) { | |
| setter = embind__requireFunction(setterSignature, setter); | |
| var setterArgumentType = types[1]; | |
| desc.set = function(v) { | |
| var ptr = validateThis(this, classType, humanName + ' setter'); | |
| var destructors = []; | |
| setter(setterContext, ptr, setterArgumentType.toWireType(destructors, v)); | |
| runDestructors(destructors); | |
| }; | |
| } | |
| Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, desc); | |
| return []; | |
| }); | |
| return []; | |
| }); | |
| }, | |
| _embind_register_class_class_function__deps: [ | |
| '$craftInvokerFunction', '$ensureOverloadTable', '$heap32VectorToArray', | |
| '$AsciiToString', '$embind__requireFunction', '$throwUnboundTypeError', | |
| '$whenDependentTypesAreResolved', '$getFunctionName'], | |
| _embind_register_class_class_function: (rawClassType, | |
| methodName, | |
| argCount, | |
| rawArgTypesAddr, | |
| invokerSignature, | |
| rawInvoker, | |
| fn, | |
| isAsync, | |
| isNonnullReturn) => { | |
| var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); | |
| methodName = AsciiToString(methodName); | |
| methodName = getFunctionName(methodName); | |
| rawInvoker = embind__requireFunction(invokerSignature, rawInvoker, isAsync); | |
| whenDependentTypesAreResolved([], [rawClassType], (classType) => { | |
| classType = classType[0]; | |
| var humanName = `${classType.name}.${methodName}`; | |
| function unboundTypesHandler() { | |
| throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`, rawArgTypes); | |
| } | |
| if (methodName.startsWith('@@')) { | |
| methodName = Symbol[methodName.substring(2)]; | |
| } | |
| var proto = classType.registeredClass.constructor; | |
| if (undefined === proto[methodName]) { | |
| // This is the first function to be registered with this name. | |
| unboundTypesHandler.argCount = argCount-1; | |
| proto[methodName] = unboundTypesHandler; | |
| } else { | |
| // There was an existing function with the same name registered. Set up | |
| // a function overload routing table. | |
| ensureOverloadTable(proto, methodName, humanName); | |
| proto[methodName].overloadTable[argCount-1] = unboundTypesHandler; | |
| } | |
| whenDependentTypesAreResolved([], rawArgTypes, (argTypes) => { | |
| // Replace the initial unbound-types-handler stub with the proper | |
| // function. If multiple overloads are registered, the function handlers | |
| // go into an overload table. | |
| var invokerArgsArray = [argTypes[0] /* return value */, null /* no class 'this'*/].concat(argTypes.slice(1) /* actual params */); | |
| var func = craftInvokerFunction(humanName, invokerArgsArray, null /* no class 'this'*/, rawInvoker, fn, isAsync); | |
| if (undefined === proto[methodName].overloadTable) { | |
| func.argCount = argCount-1; | |
| proto[methodName] = func; | |
| } else { | |
| proto[methodName].overloadTable[argCount-1] = func; | |
| } | |
| if (classType.registeredClass.__derivedClasses) { | |
| for (const derivedClass of classType.registeredClass.__derivedClasses) { | |
| if (!derivedClass.constructor.hasOwnProperty(methodName)) { | |
| // TODO: Add support for overloads | |
| derivedClass.constructor[methodName] = func; | |
| } | |
| } | |
| } | |
| return []; | |
| }); | |
| return []; | |
| }); | |
| }, | |
| _embind_register_class_class_property__deps: [ | |
| '$AsciiToString', '$embind__requireFunction', '$runDestructors', | |
| '$throwBindingError', '$throwUnboundTypeError', | |
| '$whenDependentTypesAreResolved'], | |
| _embind_register_class_class_property: (rawClassType, | |
| fieldName, | |
| rawFieldType, | |
| rawFieldPtr, | |
| getterSignature, | |
| getter, | |
| setterSignature, | |
| setter) => { | |
| fieldName = AsciiToString(fieldName); | |
| getter = embind__requireFunction(getterSignature, getter); | |
| whenDependentTypesAreResolved([], [rawClassType], (classType) => { | |
| classType = classType[0]; | |
| var humanName = `${classType.name}.${fieldName}`; | |
| var desc = { | |
| get() { | |
| throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [rawFieldType]); | |
| }, | |
| enumerable: true, | |
| configurable: true | |
| }; | |
| if (setter) { | |
| desc.set = () => { | |
| throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [rawFieldType]); | |
| }; | |
| } else { | |
| desc.set = (v) => { | |
| throwBindingError(`${humanName} is a read-only property`); | |
| }; | |
| } | |
| Object.defineProperty(classType.registeredClass.constructor, fieldName, desc); | |
| whenDependentTypesAreResolved([], [rawFieldType], (fieldType) => { | |
| fieldType = fieldType[0]; | |
| var desc = { | |
| get() { | |
| return fieldType.fromWireType(getter(rawFieldPtr)); | |
| }, | |
| enumerable: true | |
| }; | |
| if (setter) { | |
| setter = embind__requireFunction(setterSignature, setter); | |
| desc.set = (v) => { | |
| var destructors = []; | |
| setter(rawFieldPtr, fieldType.toWireType(destructors, v)); | |
| runDestructors(destructors); | |
| }; | |
| } | |
| Object.defineProperty(classType.registeredClass.constructor, fieldName, desc); | |
| return []; | |
| }); | |
| return []; | |
| }); | |
| }, | |
| _embind_create_inheriting_constructor__deps: [ | |
| '$createNamedFunction', '$Emval', | |
| '$PureVirtualError', '$AsciiToString', | |
| '$registerInheritedInstance', | |
| '$requireRegisteredType', '$throwBindingError', | |
| '$unregisterInheritedInstance', '$detachFinalizer', '$attachFinalizer'], | |
| _embind_create_inheriting_constructor: (constructorName, wrapperType, properties) => { | |
| constructorName = AsciiToString(constructorName); | |
| wrapperType = requireRegisteredType(wrapperType, 'wrapper'); | |
| properties = Emval.toValue(properties); | |
| var registeredClass = wrapperType.registeredClass; | |
| var wrapperPrototype = registeredClass.instancePrototype; | |
| var baseClass = registeredClass.baseClass; | |
| var baseClassPrototype = baseClass.instancePrototype; | |
| var baseConstructor = registeredClass.baseClass.constructor; | |
| var ctor = createNamedFunction(constructorName, function(...args) { | |
| for (var name of registeredClass.baseClass.pureVirtualFunctions) { | |
| if (this[name] === baseClassPrototype[name]) { | |
| throw new PureVirtualError(`Pure virtual function ${name} must be implemented in JavaScript`); | |
| } | |
| } | |
| Object.defineProperty(this, '__parent', { | |
| value: wrapperPrototype | |
| }); | |
| this['__construct'](...args); | |
| }); | |
| // It's a little nasty that we're modifying the wrapper prototype here. | |
| wrapperPrototype['__construct'] = function __construct(...args) { | |
| if (this === wrapperPrototype) { | |
| throwBindingError("Pass correct 'this' to __construct"); | |
| } | |
| var inner = baseConstructor['implement'](this, ...args); | |
| detachFinalizer(inner); | |
| var $$ = inner.$$; | |
| inner['notifyOnDestruction'](); | |
| $$.preservePointerOnDelete = true; | |
| Object.defineProperties(this, { $$: { | |
| value: $$ | |
| }}); | |
| attachFinalizer(this); | |
| registerInheritedInstance(registeredClass, $$.ptr, this); | |
| }; | |
| wrapperPrototype['__destruct'] = function __destruct() { | |
| if (this === wrapperPrototype) { | |
| throwBindingError("Pass correct 'this' to __destruct"); | |
| } | |
| detachFinalizer(this); | |
| unregisterInheritedInstance(registeredClass, this.$$.ptr); | |
| }; | |
| ctor.prototype = Object.create(wrapperPrototype); | |
| Object.assign(ctor.prototype, properties); | |
| return Emval.toHandle(ctor); | |
| }, | |
| $char_0: '0'.charCodeAt(0), | |
| $char_9: '9'.charCodeAt(0), | |
| $makeLegalFunctionName__deps: ['$char_0', '$char_9'], | |
| $makeLegalFunctionName: (name) => { | |
| #if ASSERTIONS | |
| assert(typeof name === 'string'); | |
| #endif | |
| name = name.replace(/[^a-zA-Z0-9_]/g, '$'); | |
| var f = name.charCodeAt(0); | |
| if (f >= char_0 && f <= char_9) { | |
| return `_${name}`; | |
| } | |
| return name; | |
| }, | |
| _embind_register_smart_ptr__deps: ['$RegisteredPointer', '$embind__requireFunction', '$whenDependentTypesAreResolved'], | |
| _embind_register_smart_ptr: (rawType, | |
| rawPointeeType, | |
| name, | |
| sharingPolicy, | |
| getPointeeSignature, | |
| rawGetPointee, | |
| constructorSignature, | |
| rawConstructor, | |
| shareSignature, | |
| rawShare, | |
| destructorSignature, | |
| rawDestructor) => { | |
| name = AsciiToString(name); | |
| rawGetPointee = embind__requireFunction(getPointeeSignature, rawGetPointee); | |
| rawConstructor = embind__requireFunction(constructorSignature, rawConstructor); | |
| rawShare = embind__requireFunction(shareSignature, rawShare); | |
| rawDestructor = embind__requireFunction(destructorSignature, rawDestructor); | |
| whenDependentTypesAreResolved([rawType], [rawPointeeType], (pointeeType) => { | |
| pointeeType = pointeeType[0]; | |
| var registeredPointer = new RegisteredPointer(name, | |
| pointeeType.registeredClass, | |
| false, | |
| false, | |
| // smart pointer properties | |
| true, | |
| pointeeType, | |
| sharingPolicy, | |
| rawGetPointee, | |
| rawConstructor, | |
| rawShare, | |
| rawDestructor); | |
| return [registeredPointer]; | |
| }); | |
| }, | |
| _embind_register_enum__docs: '/** @suppress {globalThis} */', | |
| _embind_register_enum__deps: ['$exposePublicSymbol', '$enumReadValueFromPointer', | |
| '$AsciiToString', '$registerType', '$getEnumValueType'], | |
| _embind_register_enum: (rawType, name, size, isSigned, rawValueType) => { | |
| name = AsciiToString(name); | |
| const valueType = getEnumValueType(rawValueType); | |
| switch (valueType) { | |
| case 'object': { | |
| function ctor() {} | |
| ctor.values = {}; | |
| registerType(rawType, { | |
| name, | |
| constructor: ctor, | |
| valueType, | |
| fromWireType: function(c) { | |
| return this.constructor.values[c]; | |
| }, | |
| toWireType: (destructors, c) => c.value, | |
| readValueFromPointer: enumReadValueFromPointer(name, size, isSigned), | |
| destructorFunction: null, | |
| }); | |
| exposePublicSymbol(name, ctor); | |
| break; | |
| } | |
| case 'number': { | |
| var keysMap = {}; | |
| registerType(rawType, { | |
| name: name, | |
| keysMap, | |
| valueType, | |
| fromWireType: (c) => c, | |
| toWireType: (destructors, c) => c, | |
| readValueFromPointer: enumReadValueFromPointer(name, size, isSigned), | |
| destructorFunction: null, | |
| }); | |
| exposePublicSymbol(name, keysMap); | |
| // Just exposes a simple dict. argCount is meaningless here, | |
| delete Module[name].argCount; | |
| break; | |
| } | |
| case 'string': { | |
| var valuesMap = {}; | |
| var reverseMap = {}; | |
| var keysMap = {}; | |
| registerType(rawType, { | |
| name: name, | |
| valuesMap, | |
| reverseMap, | |
| keysMap, | |
| valueType, | |
| fromWireType: function(c) { | |
| return this.reverseMap[c]; | |
| }, | |
| toWireType: function(destructors, c) { | |
| return this.valuesMap[c]; | |
| }, | |
| readValueFromPointer: enumReadValueFromPointer(name, size, isSigned), | |
| destructorFunction: null, | |
| }); | |
| exposePublicSymbol(name, keysMap); | |
| // Just exposes a simple dict. argCount is meaningless here, | |
| delete Module[name].argCount; | |
| break; | |
| } | |
| } | |
| }, | |
| _embind_register_enum_value__deps: ['$createNamedFunction', '$AsciiToString', '$requireRegisteredType'], | |
| _embind_register_enum_value: (rawEnumType, name, enumValue) => { | |
| var enumType = requireRegisteredType(rawEnumType, 'enum'); | |
| name = AsciiToString(name); | |
| switch (enumType.valueType) { | |
| case 'object': { | |
| var Enum = enumType.constructor; | |
| var Value = Object.create(enumType.constructor.prototype, { | |
| value: {value: enumValue}, | |
| constructor: {value: createNamedFunction(`${enumType.name}_${name}`, function() {})}, | |
| }); | |
| Enum.values[enumValue] = Value; | |
| Enum[name] = Value; | |
| break; | |
| } | |
| case 'number': { | |
| enumType.keysMap[name] = enumValue; | |
| break; | |
| } | |
| case 'string': { | |
| enumType.valuesMap[name] = enumValue; | |
| enumType.reverseMap[enumValue] = name; | |
| enumType.keysMap[name] = name; | |
| break; | |
| } | |
| } | |
| }, | |
| _embind_register_constant__deps: ['$AsciiToString', '$whenDependentTypesAreResolved'], | |
| _embind_register_constant: (name, type, value) => { | |
| name = AsciiToString(name); | |
| whenDependentTypesAreResolved([], [type], (type) => { | |
| type = type[0]; | |
| Module[name] = type.fromWireType(value); | |
| return []; | |
| }); | |
| }, | |
| }; | |
| addToLibrary(LibraryEmbind); | |
Xet Storage Details
- Size:
- 84.6 kB
- Xet hash:
- 83b5f9542d177eea3a137072b310ac9fb1d09a82ddf991daf86093895b84ef74
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.