Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/src/lib/libembind.js
4150 views
1
// Copyright 2012 The Emscripten Authors. All rights reserved.
2
// Emscripten is available under two separate licenses, the MIT license and the
3
// University of Illinois/NCSA Open Source License. Both these licenses can be
4
// found in the LICENSE file.
5
6
#include "libembind_shared.js"
7
8
var LibraryEmbind = {
9
$UnboundTypeError: class extends Error {},
10
$PureVirtualError: class extends Error {},
11
#if EMBIND_AOT
12
$InvokerFunctions: '<<< EMBIND_AOT_INVOKERS >>>',
13
#endif
14
// If register_type is used, emval will be registered multiple times for
15
// different type id's, but only a single type object is needed on the JS side
16
// for all of them. Store the type for reuse.
17
$EmValType__deps: ['_emval_decref', '$Emval', '$readPointer'],
18
$EmValType: `{
19
name: 'emscripten::val',
20
fromWireType: (handle) => {
21
var rv = Emval.toValue(handle);
22
__emval_decref(handle);
23
return rv;
24
},
25
toWireType: (destructors, value) => Emval.toHandle(value),
26
readValueFromPointer: readPointer,
27
destructorFunction: null, // This type does not need a destructor
28
29
// TODO: do we need a deleteObject here? write a test where
30
// emval is passed into JS via an interface
31
}`,
32
$EmValOptionalType__deps: ['$EmValType'],
33
$EmValOptionalType: '=Object.assign({optional: true}, EmValType);',
34
35
$throwUnboundTypeError__deps: ['$registeredTypes', '$typeDependencies', '$UnboundTypeError', '$getTypeName'],
36
$throwUnboundTypeError: (message, types) => {
37
var unboundTypes = [];
38
var seen = {};
39
function visit(type) {
40
if (seen[type]) {
41
return;
42
}
43
if (registeredTypes[type]) {
44
return;
45
}
46
if (typeDependencies[type]) {
47
typeDependencies[type].forEach(visit);
48
return;
49
}
50
unboundTypes.push(type);
51
seen[type] = true;
52
}
53
types.forEach(visit);
54
55
throw new UnboundTypeError(`${message}: ` + unboundTypes.map(getTypeName).join([', ']));
56
},
57
58
// Creates a function overload resolution table to the given method 'methodName' in the given prototype,
59
// if the overload table doesn't yet exist.
60
$ensureOverloadTable__deps: ['$throwBindingError'],
61
$ensureOverloadTable: (proto, methodName, humanName) => {
62
if (undefined === proto[methodName].overloadTable) {
63
var prevFunc = proto[methodName];
64
// Inject an overload resolver function that routes to the appropriate overload based on the number of arguments.
65
proto[methodName] = function(...args) {
66
// TODO This check can be removed in -O3 level "unsafe" optimizations.
67
if (!proto[methodName].overloadTable.hasOwnProperty(args.length)) {
68
throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${args.length}) - expects one of (${proto[methodName].overloadTable})!`);
69
}
70
return proto[methodName].overloadTable[args.length].apply(this, args);
71
};
72
// Move the previous function into the overload table.
73
proto[methodName].overloadTable = [];
74
proto[methodName].overloadTable[prevFunc.argCount] = prevFunc;
75
}
76
},
77
78
/*
79
Registers a symbol (function, class, enum, ...) as part of the Module JS object so that
80
hand-written code is able to access that symbol via 'Module.name'.
81
name: The name of the symbol that's being exposed.
82
value: The object itself to expose (function, class, ...)
83
numArguments: For functions, specifies the number of arguments the function takes in. For other types, unused and undefined.
84
85
To implement support for multiple overloads of a function, an 'overload selector' function is used. That selector function chooses
86
the appropriate overload to call from an function overload table. This selector function is only used if multiple overloads are
87
actually registered, since it carries a slight performance penalty. */
88
$exposePublicSymbol__deps: ['$ensureOverloadTable', '$throwBindingError'],
89
$exposePublicSymbol__docs: '/** @param {number=} numArguments */',
90
$exposePublicSymbol: (name, value, numArguments) => {
91
if (Module.hasOwnProperty(name)) {
92
if (undefined === numArguments || (undefined !== Module[name].overloadTable && undefined !== Module[name].overloadTable[numArguments])) {
93
throwBindingError(`Cannot register public name '${name}' twice`);
94
}
95
96
// We are exposing a function with the same name as an existing function. Create an overload table and a function selector
97
// that routes between the two.
98
ensureOverloadTable(Module, name, name);
99
if (Module[name].overloadTable.hasOwnProperty(numArguments)) {
100
throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`);
101
}
102
// Add the new function into the overload table.
103
Module[name].overloadTable[numArguments] = value;
104
} else {
105
Module[name] = value;
106
Module[name].argCount = numArguments;
107
}
108
},
109
110
$replacePublicSymbol__deps: ['$throwInternalError'],
111
$replacePublicSymbol__docs: '/** @param {number=} numArguments */',
112
$replacePublicSymbol: (name, value, numArguments) => {
113
if (!Module.hasOwnProperty(name)) {
114
throwInternalError('Replacing nonexistent public symbol');
115
}
116
// If there's an overload table for this symbol, replace the symbol in the overload table instead.
117
if (undefined !== Module[name].overloadTable && undefined !== numArguments) {
118
Module[name].overloadTable[numArguments] = value;
119
} else {
120
Module[name] = value;
121
Module[name].argCount = numArguments;
122
}
123
},
124
125
$createNamedFunction: (name, func) => Object.defineProperty(func, 'name', { value: name }),
126
127
$embindRepr: (v) => {
128
if (v === null) {
129
return 'null';
130
}
131
var t = typeof v;
132
if (t === 'object' || t === 'array' || t === 'function') {
133
return v.toString();
134
} else {
135
return '' + v;
136
}
137
},
138
139
// raw pointer -> instance
140
$registeredInstances: {},
141
142
$getBasestPointer__deps: ['$throwBindingError'],
143
$getBasestPointer: (class_, ptr) => {
144
if (ptr === undefined) {
145
throwBindingError('ptr should not be undefined');
146
}
147
while (class_.baseClass) {
148
ptr = class_.upcast(ptr);
149
class_ = class_.baseClass;
150
}
151
return ptr;
152
},
153
154
$registerInheritedInstance__deps: ['$registeredInstances', '$getBasestPointer', '$throwBindingError'],
155
$registerInheritedInstance: (class_, ptr, instance) => {
156
ptr = getBasestPointer(class_, ptr);
157
if (registeredInstances.hasOwnProperty(ptr)) {
158
throwBindingError(`Tried to register registered instance: ${ptr}`);
159
} else {
160
registeredInstances[ptr] = instance;
161
}
162
},
163
164
$unregisterInheritedInstance__deps: ['$registeredInstances', '$getBasestPointer', '$throwBindingError'],
165
$unregisterInheritedInstance: (class_, ptr) => {
166
ptr = getBasestPointer(class_, ptr);
167
if (registeredInstances.hasOwnProperty(ptr)) {
168
delete registeredInstances[ptr];
169
} else {
170
throwBindingError(`Tried to unregister unregistered instance: ${ptr}`);
171
}
172
},
173
174
$getInheritedInstance__deps: ['$registeredInstances', '$getBasestPointer'],
175
$getInheritedInstance: (class_, ptr) => {
176
ptr = getBasestPointer(class_, ptr);
177
return registeredInstances[ptr];
178
},
179
180
$getInheritedInstanceCount__deps: ['$registeredInstances'],
181
$getInheritedInstanceCount: () => Object.keys(registeredInstances).length,
182
183
$getLiveInheritedInstances__deps: ['$registeredInstances'],
184
$getLiveInheritedInstances: () => {
185
var rv = [];
186
for (var k in registeredInstances) {
187
if (registeredInstances.hasOwnProperty(k)) {
188
rv.push(registeredInstances[k]);
189
}
190
}
191
return rv;
192
},
193
194
// class typeID -> {pointerType: ..., constPointerType: ...}
195
$registeredPointers: {},
196
197
$registerType__deps: ['$sharedRegisterType'],
198
$registerType__docs: '/** @param {Object=} options */',
199
$registerType: function(rawType, registeredInstance, options = {}) {
200
return sharedRegisterType(rawType, registeredInstance, options);
201
},
202
203
_embind_register_void__deps: ['$AsciiToString', '$registerType'],
204
_embind_register_void: (rawType, name) => {
205
name = AsciiToString(name);
206
registerType(rawType, {
207
isVoid: true, // void return values can be optimized out sometimes
208
name,
209
fromWireType: () => undefined,
210
// TODO: assert if anything else is given?
211
toWireType: (destructors, o) => undefined,
212
});
213
},
214
215
_embind_register_bool__docs: '/** @suppress {globalThis} */',
216
_embind_register_bool__deps: ['$AsciiToString', '$registerType'],
217
_embind_register_bool: (rawType, name, trueValue, falseValue) => {
218
name = AsciiToString(name);
219
registerType(rawType, {
220
name,
221
fromWireType: function(wt) {
222
// ambiguous emscripten ABI: sometimes return values are
223
// true or false, and sometimes integers (0 or 1)
224
return !!wt;
225
},
226
toWireType: function(destructors, o) {
227
return o ? trueValue : falseValue;
228
},
229
readValueFromPointer: function(pointer) {
230
return this.fromWireType(HEAPU8[pointer]);
231
},
232
destructorFunction: null, // This type does not need a destructor
233
});
234
},
235
236
$integerReadValueFromPointer__deps: [],
237
$integerReadValueFromPointer: (name, width, signed) => {
238
// integers are quite common, so generate very specialized functions
239
switch (width) {
240
case 1: return signed ?
241
(pointer) => {{{ makeGetValue('pointer', 0, 'i8') }}} :
242
(pointer) => {{{ makeGetValue('pointer', 0, 'u8') }}};
243
case 2: return signed ?
244
(pointer) => {{{ makeGetValue('pointer', 0, 'i16') }}} :
245
(pointer) => {{{ makeGetValue('pointer', 0, 'u16') }}}
246
case 4: return signed ?
247
(pointer) => {{{ makeGetValue('pointer', 0, 'i32') }}} :
248
(pointer) => {{{ makeGetValue('pointer', 0, 'u32') }}}
249
#if WASM_BIGINT
250
case 8: return signed ?
251
(pointer) => {{{ makeGetValue('pointer', 0, 'i64') }}} :
252
(pointer) => {{{ makeGetValue('pointer', 0, 'u64') }}}
253
#endif
254
default:
255
throw new TypeError(`invalid integer width (${width}): ${name}`);
256
}
257
},
258
259
$enumReadValueFromPointer__deps: [],
260
$enumReadValueFromPointer: (name, width, signed) => {
261
switch (width) {
262
case 1: return signed ?
263
function(pointer) { return this.fromWireType({{{ makeGetValue('pointer', 0, 'i8') }}}) } :
264
function(pointer) { return this.fromWireType({{{ makeGetValue('pointer', 0, 'u8') }}}) };
265
case 2: return signed ?
266
function(pointer) { return this.fromWireType({{{ makeGetValue('pointer', 0, 'i16') }}}) } :
267
function(pointer) { return this.fromWireType({{{ makeGetValue('pointer', 0, 'u16') }}}) };
268
case 4: return signed ?
269
function(pointer) { return this.fromWireType({{{ makeGetValue('pointer', 0, 'i32') }}}) } :
270
function(pointer) { return this.fromWireType({{{ makeGetValue('pointer', 0, 'u32') }}}) };
271
default:
272
throw new TypeError(`invalid integer width (${width}): ${name}`);
273
}
274
},
275
276
$floatReadValueFromPointer__deps: [],
277
$floatReadValueFromPointer: (name, width) => {
278
switch (width) {
279
case 4: return function(pointer) {
280
return this.fromWireType({{{ makeGetValue('pointer', 0, 'float') }}});
281
};
282
case 8: return function(pointer) {
283
return this.fromWireType({{{ makeGetValue('pointer', 0, 'double') }}});
284
};
285
default:
286
throw new TypeError(`invalid float width (${width}): ${name}`);
287
}
288
},
289
290
#if ASSERTIONS
291
$assertIntegerRange__deps: ['$embindRepr'],
292
$assertIntegerRange: (typeName, value, minRange, maxRange) => {
293
if (value < minRange || value > maxRange) {
294
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}]!`);
295
}
296
},
297
#endif
298
299
_embind_register_integer__docs: '/** @suppress {globalThis} */',
300
// When converting a number from JS to C++ side, the valid range of the number is
301
// [minRange, maxRange], inclusive.
302
_embind_register_integer__deps: [
303
'$integerReadValueFromPointer', '$AsciiToString', '$registerType',
304
#if ASSERTIONS
305
'$embindRepr',
306
'$assertIntegerRange',
307
#endif
308
],
309
_embind_register_integer: (primitiveType, name, size, minRange, maxRange) => {
310
name = AsciiToString(name);
311
312
const isUnsignedType = minRange === 0;
313
314
let fromWireType = (value) => value;
315
if (isUnsignedType) {
316
var bitshift = 32 - 8*size;
317
fromWireType = (value) => (value << bitshift) >>> bitshift;
318
maxRange = fromWireType(maxRange);
319
}
320
321
registerType(primitiveType, {
322
name,
323
fromWireType: fromWireType,
324
toWireType: (destructors, value) => {
325
#if ASSERTIONS
326
if (typeof value != "number" && typeof value != "boolean") {
327
throw new TypeError(`Cannot convert "${embindRepr(value)}" to ${name}`);
328
}
329
assertIntegerRange(name, value, minRange, maxRange);
330
#endif
331
// The VM will perform JS to Wasm value conversion, according to the spec:
332
// https://www.w3.org/TR/wasm-js-api-1/#towebassemblyvalue
333
return value;
334
},
335
readValueFromPointer: integerReadValueFromPointer(name, size, minRange !== 0),
336
destructorFunction: null, // This type does not need a destructor
337
});
338
},
339
340
#if WASM_BIGINT
341
_embind_register_bigint__docs: '/** @suppress {globalThis} */',
342
_embind_register_bigint__deps: [
343
'$AsciiToString', '$registerType', '$integerReadValueFromPointer',
344
#if ASSERTIONS
345
'$embindRepr',
346
'$assertIntegerRange',
347
#endif
348
],
349
_embind_register_bigint: (primitiveType, name, size, minRange, maxRange) => {
350
name = AsciiToString(name);
351
352
const isUnsignedType = minRange === 0n;
353
354
let fromWireType = (value) => value;
355
if (isUnsignedType) {
356
// uint64 get converted to int64 in ABI, fix them up like we do for 32-bit integers.
357
const bitSize = size * 8;
358
fromWireType = (value) => {
359
#if MEMORY64
360
// FIXME(https://github.com/emscripten-core/emscripten/issues/16975)
361
// `size_t` ends up here, but it's transferred in the ABI as a plain number instead of a bigint.
362
if (typeof value == 'number') {
363
return value >>> 0;
364
}
365
#endif
366
return BigInt.asUintN(bitSize, value);
367
}
368
maxRange = fromWireType(maxRange);
369
}
370
371
registerType(primitiveType, {
372
name,
373
fromWireType: fromWireType,
374
toWireType: (destructors, value) => {
375
if (typeof value == "number") {
376
value = BigInt(value);
377
}
378
#if ASSERTIONS
379
else if (typeof value != "bigint") {
380
throw new TypeError(`Cannot convert "${embindRepr(value)}" to ${this.name}`);
381
}
382
assertIntegerRange(name, value, minRange, maxRange);
383
#endif
384
return value;
385
},
386
readValueFromPointer: integerReadValueFromPointer(name, size, !isUnsignedType),
387
destructorFunction: null, // This type does not need a destructor
388
});
389
},
390
#else
391
_embind_register_bigint__deps: [],
392
_embind_register_bigint: (primitiveType, name, size, minRange, maxRange) => {},
393
#endif
394
395
_embind_register_float__deps: [
396
'$floatReadValueFromPointer', '$AsciiToString', '$registerType',
397
#if ASSERTIONS
398
'$embindRepr',
399
#endif
400
],
401
_embind_register_float: (rawType, name, size) => {
402
name = AsciiToString(name);
403
registerType(rawType, {
404
name,
405
fromWireType: (value) => value,
406
toWireType: (destructors, value) => {
407
#if ASSERTIONS
408
if (typeof value != "number" && typeof value != "boolean") {
409
throw new TypeError(`Cannot convert ${embindRepr(value)} to ${this.name}`);
410
}
411
#endif
412
// The VM will perform JS to Wasm value conversion, according to the spec:
413
// https://www.w3.org/TR/wasm-js-api-1/#towebassemblyvalue
414
return value;
415
},
416
readValueFromPointer: floatReadValueFromPointer(name, size),
417
destructorFunction: null, // This type does not need a destructor
418
});
419
},
420
421
$readPointer__docs: '/** @suppress {globalThis} */',
422
$readPointer: function(pointer) {
423
return this.fromWireType({{{ makeGetValue('pointer', '0', '*') }}});
424
},
425
426
_embind_register_std_string__deps: [
427
'$AsciiToString', '$registerType',
428
'$readPointer', '$throwBindingError',
429
'$stringToUTF8', '$lengthBytesUTF8', 'malloc', 'free'],
430
_embind_register_std_string: (rawType, name) => {
431
name = AsciiToString(name);
432
var stdStringIsUTF8 = {{{ EMBIND_STD_STRING_IS_UTF8 }}};
433
434
registerType(rawType, {
435
name,
436
// For some method names we use string keys here since they are part of
437
// the public/external API and/or used by the runtime-generated code.
438
fromWireType(value) {
439
var length = {{{ makeGetValue('value', '0', '*') }}};
440
var payload = value + {{{ POINTER_SIZE }}};
441
442
var str;
443
if (stdStringIsUTF8) {
444
str = UTF8ToString(payload, length, true);
445
} else {
446
str = '';
447
for (var i = 0; i < length; ++i) {
448
str += String.fromCharCode(HEAPU8[payload + i]);
449
}
450
}
451
452
_free(value);
453
454
return str;
455
},
456
toWireType(destructors, value) {
457
if (value instanceof ArrayBuffer) {
458
value = new Uint8Array(value);
459
}
460
461
var length;
462
var valueIsOfTypeString = (typeof value == 'string');
463
464
// We accept `string` or array views with single byte elements
465
if (!(valueIsOfTypeString || (ArrayBuffer.isView(value) && value.BYTES_PER_ELEMENT == 1))) {
466
throwBindingError('Cannot pass non-string to std::string');
467
}
468
if (stdStringIsUTF8 && valueIsOfTypeString) {
469
length = lengthBytesUTF8(value);
470
} else {
471
length = value.length;
472
}
473
474
// assumes POINTER_SIZE alignment
475
var base = _malloc({{{ POINTER_SIZE }}} + length + 1);
476
var ptr = base + {{{ POINTER_SIZE }}};
477
{{{ makeSetValue('base', '0', 'length', SIZE_TYPE) }}};
478
if (valueIsOfTypeString) {
479
if (stdStringIsUTF8) {
480
stringToUTF8(value, ptr, length + 1);
481
} else {
482
for (var i = 0; i < length; ++i) {
483
var charCode = value.charCodeAt(i);
484
if (charCode > 255) {
485
_free(base);
486
throwBindingError('String has UTF-16 code units that do not fit in 8 bits');
487
}
488
HEAPU8[ptr + i] = charCode;
489
}
490
}
491
} else {
492
HEAPU8.set(value, ptr);
493
}
494
495
if (destructors !== null) {
496
destructors.push(_free, base);
497
}
498
return base;
499
},
500
readValueFromPointer: readPointer,
501
destructorFunction(ptr) {
502
_free(ptr);
503
},
504
});
505
},
506
507
_embind_register_std_wstring__deps: [
508
'$AsciiToString', '$registerType', '$readPointer',
509
'$UTF16ToString', '$stringToUTF16', '$lengthBytesUTF16',
510
'$UTF32ToString', '$stringToUTF32', '$lengthBytesUTF32',
511
],
512
_embind_register_std_wstring: (rawType, charSize, name) => {
513
name = AsciiToString(name);
514
var decodeString, encodeString, lengthBytesUTF;
515
if (charSize === 2) {
516
decodeString = UTF16ToString;
517
encodeString = stringToUTF16;
518
lengthBytesUTF = lengthBytesUTF16;
519
} else {
520
#if ASSERTIONS
521
assert(charSize === 4, 'only 2-byte and 4-byte strings are currently supported');
522
#endif
523
decodeString = UTF32ToString;
524
encodeString = stringToUTF32;
525
lengthBytesUTF = lengthBytesUTF32;
526
}
527
registerType(rawType, {
528
name,
529
fromWireType: (value) => {
530
// Code mostly taken from _embind_register_std_string fromWireType
531
var length = {{{ makeGetValue('value', 0, '*') }}};
532
var str = decodeString(value + {{{ POINTER_SIZE }}}, length * charSize, true);
533
534
_free(value);
535
536
return str;
537
},
538
toWireType: (destructors, value) => {
539
if (!(typeof value == 'string')) {
540
throwBindingError(`Cannot pass non-string to C++ string type ${name}`);
541
}
542
543
// assumes POINTER_SIZE alignment
544
var length = lengthBytesUTF(value);
545
var ptr = _malloc({{{ POINTER_SIZE }}} + length + charSize);
546
{{{ makeSetValue('ptr', '0', 'length / charSize', SIZE_TYPE) }}};
547
548
encodeString(value, ptr + {{{ POINTER_SIZE }}}, length + charSize);
549
550
if (destructors !== null) {
551
destructors.push(_free, ptr);
552
}
553
return ptr;
554
},
555
readValueFromPointer: readPointer,
556
destructorFunction(ptr) {
557
_free(ptr);
558
}
559
});
560
},
561
562
_embind_register_emval__deps: [
563
'$registerType', '$EmValType'],
564
_embind_register_emval: (rawType) => registerType(rawType, EmValType),
565
566
_embind_register_user_type__deps: ['_embind_register_emval'],
567
_embind_register_user_type: (rawType, name) => {
568
__embind_register_emval(rawType);
569
},
570
571
_embind_register_optional__deps: ['$registerType', '$EmValOptionalType'],
572
_embind_register_optional: (rawOptionalType, rawType) => {
573
registerType(rawOptionalType, EmValOptionalType);
574
},
575
576
_embind_register_memory_view__deps: ['$AsciiToString', '$registerType'],
577
_embind_register_memory_view: (rawType, dataTypeIndex, name) => {
578
var typeMapping = [
579
Int8Array,
580
Uint8Array,
581
Int16Array,
582
Uint16Array,
583
Int32Array,
584
Uint32Array,
585
Float32Array,
586
Float64Array,
587
#if WASM_BIGINT
588
BigInt64Array,
589
BigUint64Array,
590
#endif
591
];
592
593
var TA = typeMapping[dataTypeIndex];
594
595
function decodeMemoryView(handle) {
596
var size = {{{ makeGetValue('handle', 0, '*') }}};
597
var data = {{{ makeGetValue('handle', POINTER_SIZE, '*') }}};
598
return new TA(HEAP8.buffer, data, size);
599
}
600
601
name = AsciiToString(name);
602
registerType(rawType, {
603
name,
604
fromWireType: decodeMemoryView,
605
readValueFromPointer: decodeMemoryView,
606
}, {
607
ignoreDuplicateRegistrations: true,
608
});
609
},
610
611
$runDestructors: (destructors) => {
612
while (destructors.length) {
613
var ptr = destructors.pop();
614
var del = destructors.pop();
615
del(ptr);
616
}
617
},
618
619
// The path to interop from JS code to C++ code:
620
// (hand-written JS code) -> (autogenerated JS invoker) -> (template-generated C++ invoker) -> (target C++ function)
621
// craftInvokerFunction generates the JS invoker function for each function exposed to JS through embind.
622
$craftInvokerFunction__deps: [
623
'$createNamedFunction', '$runDestructors', '$throwBindingError', '$usesDestructorStack',
624
#if DYNAMIC_EXECUTION && !EMBIND_AOT
625
'$createJsInvoker',
626
#endif
627
#if EMBIND_AOT
628
'$InvokerFunctions',
629
'$createJsInvokerSignature',
630
#endif
631
#if ASYNCIFY == 1
632
'$Asyncify',
633
#endif
634
#if ASSERTIONS
635
'$getRequiredArgCount',
636
'$checkArgCount',
637
#endif
638
],
639
$craftInvokerFunction: function(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc, /** boolean= */ isAsync) {
640
// humanName: a human-readable string name for the function to be generated.
641
// argTypes: An array that contains the embind type objects for all types in the function signature.
642
// argTypes[0] is the type object for the function return value.
643
// argTypes[1] is the type object for function this object/class type, or null if not crafting an invoker for a class method.
644
// argTypes[2...] are the actual function parameters.
645
// classType: The embind type object for the class to be bound, or null if this is not a method of a class.
646
// cppInvokerFunc: JS Function object to the C++-side function that interops into C++ code.
647
// cppTargetFunc: Function pointer (an integer to FUNCTION_TABLE) to the target C++ function the cppInvokerFunc will end up calling.
648
// isAsync: Optional. If true, returns an async function. Async bindings are only supported with JSPI.
649
var argCount = argTypes.length;
650
651
if (argCount < 2) {
652
throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!");
653
}
654
655
#if ASSERTIONS && ASYNCIFY != 2
656
assert(!isAsync, 'Async bindings are only supported with JSPI.');
657
#endif
658
var isClassMethodFunc = (argTypes[1] !== null && classType !== null);
659
660
// Free functions with signature "void function()" do not need an invoker that marshalls between wire types.
661
// TODO: This omits argument count check - enable only at -O3 or similar.
662
// if (ENABLE_UNSAFE_OPTS && argCount == 2 && argTypes[0].name == "void" && !isClassMethodFunc) {
663
// return FUNCTION_TABLE[fn];
664
// }
665
666
667
// Determine if we need to use a dynamic stack to store the destructors for the function parameters.
668
// TODO: Remove this completely once all function invokers are being dynamically generated.
669
var needsDestructorStack = usesDestructorStack(argTypes);
670
671
var returns = !argTypes[0].isVoid;
672
673
var expectedArgCount = argCount - 2;
674
#if ASSERTIONS
675
var minArgs = getRequiredArgCount(argTypes);
676
#endif
677
#if DYNAMIC_EXECUTION == 0 && !EMBIND_AOT
678
var argsWired = new Array(expectedArgCount);
679
var invokerFuncArgs = [];
680
var destructors = [];
681
var invokerFn = function(...args) {
682
#if ASSERTIONS
683
checkArgCount(args.length, minArgs, expectedArgCount, humanName, throwBindingError);
684
#endif
685
#if EMSCRIPTEN_TRACING
686
Module.emscripten_trace_enter_context(`embind::${humanName}`);
687
#endif
688
destructors.length = 0;
689
var thisWired;
690
invokerFuncArgs.length = isClassMethodFunc ? 2 : 1;
691
invokerFuncArgs[0] = cppTargetFunc;
692
if (isClassMethodFunc) {
693
thisWired = argTypes[1].toWireType(destructors, this);
694
invokerFuncArgs[1] = thisWired;
695
}
696
for (var i = 0; i < expectedArgCount; ++i) {
697
argsWired[i] = argTypes[i + 2].toWireType(destructors, args[i]);
698
invokerFuncArgs.push(argsWired[i]);
699
}
700
701
var rv = cppInvokerFunc(...invokerFuncArgs);
702
703
function onDone(rv) {
704
if (needsDestructorStack) {
705
runDestructors(destructors);
706
} else {
707
for (var i = isClassMethodFunc ? 1 : 2; i < argTypes.length; i++) {
708
var param = i === 1 ? thisWired : argsWired[i - 2];
709
if (argTypes[i].destructorFunction !== null) {
710
argTypes[i].destructorFunction(param);
711
}
712
}
713
}
714
715
#if EMSCRIPTEN_TRACING
716
Module.emscripten_trace_exit_context();
717
#endif
718
719
if (returns) {
720
return argTypes[0].fromWireType(rv);
721
}
722
}
723
724
#if ASYNCIFY == 1
725
if (Asyncify.currData) {
726
return Asyncify.whenDone().then(onDone);
727
}
728
#elif ASYNCIFY == 2
729
if (isAsync) {
730
return rv.then(onDone);
731
}
732
#endif
733
734
return onDone(rv);
735
};
736
#else
737
// Builld the arguments that will be passed into the closure around the invoker
738
// function.
739
var retType = argTypes[0];
740
var instType = argTypes[1];
741
var closureArgs = [humanName, throwBindingError, cppInvokerFunc, cppTargetFunc, runDestructors, retType.fromWireType.bind(retType), instType?.toWireType.bind(instType)];
742
#if EMSCRIPTEN_TRACING
743
closureArgs.push(Module);
744
#endif
745
for (var i = 2; i < argCount; ++i) {
746
var argType = argTypes[i];
747
closureArgs.push(argType.toWireType.bind(argType));
748
}
749
#if ASYNCIFY == 1
750
closureArgs.push(Asyncify);
751
#endif
752
if (!needsDestructorStack) {
753
// Skip return value at index 0 - it's not deleted here. Also skip class type if not a method.
754
for (var i = isClassMethodFunc?1:2; i < argTypes.length; ++i) {
755
if (argTypes[i].destructorFunction !== null) {
756
closureArgs.push(argTypes[i].destructorFunction);
757
}
758
}
759
}
760
#if ASSERTIONS
761
closureArgs.push(checkArgCount, minArgs, expectedArgCount);
762
#endif
763
764
#if EMBIND_AOT
765
var signature = createJsInvokerSignature(argTypes, isClassMethodFunc, returns, isAsync);
766
var invokerFn = InvokerFunctions[signature](...closureArgs);
767
#else
768
769
let invokerFactory = createJsInvoker(argTypes, isClassMethodFunc, returns, isAsync);
770
var invokerFn = invokerFactory(...closureArgs);
771
#endif
772
#endif
773
return createNamedFunction(humanName, invokerFn);
774
},
775
776
$embind__requireFunction__deps: ['$AsciiToString', '$throwBindingError'
777
#if DYNCALLS || !WASM_BIGINT || MEMORY64 || CAN_ADDRESS_2GB
778
, '$getDynCaller'
779
#endif
780
],
781
$embind__requireFunction: (signature, rawFunction, isAsync = false) => {
782
#if ASSERTIONS && ASYNCIFY != 2
783
assert(!isAsync, 'Async bindings are only supported with JSPI.');
784
#endif
785
786
signature = AsciiToString(signature);
787
788
function makeDynCaller() {
789
#if DYNCALLS
790
return getDynCaller(signature, rawFunction);
791
#else
792
#if !WASM_BIGINT
793
if (signature.includes('j')) {
794
return getDynCaller(signature, rawFunction);
795
}
796
#endif
797
#if MEMORY64 || CAN_ADDRESS_2GB
798
if (signature.includes('p')) {
799
return getDynCaller(signature, rawFunction, isAsync);
800
}
801
#endif
802
var rtn = getWasmTableEntry(rawFunction);
803
#if JSPI
804
if (isAsync) {
805
rtn = WebAssembly.promising(rtn);
806
}
807
#endif
808
return rtn;
809
#endif
810
}
811
812
var fp = makeDynCaller();
813
if (typeof fp != 'function') {
814
throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`);
815
}
816
return fp;
817
},
818
819
_embind_register_function__deps: [
820
'$craftInvokerFunction', '$exposePublicSymbol', '$heap32VectorToArray',
821
'$AsciiToString', '$replacePublicSymbol', '$embind__requireFunction',
822
'$throwUnboundTypeError', '$whenDependentTypesAreResolved', '$getFunctionName'],
823
_embind_register_function: (name, argCount, rawArgTypesAddr, signature, rawInvoker, fn, isAsync, isNonnullReturn) => {
824
var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
825
name = AsciiToString(name);
826
name = getFunctionName(name);
827
828
rawInvoker = embind__requireFunction(signature, rawInvoker, isAsync);
829
830
exposePublicSymbol(name, function() {
831
throwUnboundTypeError(`Cannot call ${name} due to unbound types`, argTypes);
832
}, argCount - 1);
833
834
whenDependentTypesAreResolved([], argTypes, (argTypes) => {
835
var invokerArgsArray = [argTypes[0] /* return value */, null /* no class 'this'*/].concat(argTypes.slice(1) /* actual params */);
836
replacePublicSymbol(name, craftInvokerFunction(name, invokerArgsArray, null /* no class 'this'*/, rawInvoker, fn, isAsync), argCount - 1);
837
return [];
838
});
839
},
840
841
_embind_register_value_array__deps: [
842
'$tupleRegistrations', '$AsciiToString', '$embind__requireFunction'],
843
_embind_register_value_array: (
844
rawType,
845
name,
846
constructorSignature,
847
rawConstructor,
848
destructorSignature,
849
rawDestructor
850
) => {
851
tupleRegistrations[rawType] = {
852
name: AsciiToString(name),
853
rawConstructor: embind__requireFunction(constructorSignature, rawConstructor),
854
rawDestructor: embind__requireFunction(destructorSignature, rawDestructor),
855
elements: [],
856
};
857
},
858
859
_embind_register_value_array_element__deps: [
860
'$tupleRegistrations', '$embind__requireFunction'],
861
_embind_register_value_array_element: (
862
rawTupleType,
863
getterReturnType,
864
getterSignature,
865
getter,
866
getterContext,
867
setterArgumentType,
868
setterSignature,
869
setter,
870
setterContext
871
) => {
872
tupleRegistrations[rawTupleType].elements.push({
873
getterReturnType,
874
getter: embind__requireFunction(getterSignature, getter),
875
getterContext,
876
setterArgumentType,
877
setter: embind__requireFunction(setterSignature, setter),
878
setterContext,
879
});
880
},
881
882
_embind_finalize_value_array__deps: [
883
'$tupleRegistrations', '$runDestructors',
884
'$readPointer', '$whenDependentTypesAreResolved'],
885
_embind_finalize_value_array: (rawTupleType) => {
886
var reg = tupleRegistrations[rawTupleType];
887
delete tupleRegistrations[rawTupleType];
888
var elements = reg.elements;
889
var elementsLength = elements.length;
890
var elementTypes = elements.map((elt) => elt.getterReturnType).
891
concat(elements.map((elt) => elt.setterArgumentType));
892
893
var rawConstructor = reg.rawConstructor;
894
var rawDestructor = reg.rawDestructor;
895
896
whenDependentTypesAreResolved([rawTupleType], elementTypes, (elementTypes) => {
897
elements.forEach((elt, i) => {
898
var getterReturnType = elementTypes[i];
899
var getter = elt.getter;
900
var getterContext = elt.getterContext;
901
var setterArgumentType = elementTypes[i + elementsLength];
902
var setter = elt.setter;
903
var setterContext = elt.setterContext;
904
elt.read = (ptr) => getterReturnType.fromWireType(getter(getterContext, ptr));
905
elt.write = (ptr, o) => {
906
var destructors = [];
907
setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o));
908
runDestructors(destructors);
909
};
910
});
911
912
return [{
913
name: reg.name,
914
fromWireType: (ptr) => {
915
var rv = new Array(elementsLength);
916
for (var i = 0; i < elementsLength; ++i) {
917
rv[i] = elements[i].read(ptr);
918
}
919
rawDestructor(ptr);
920
return rv;
921
},
922
toWireType: (destructors, o) => {
923
if (elementsLength !== o.length) {
924
throw new TypeError(`Incorrect number of tuple elements for ${reg.name}: expected=${elementsLength}, actual=${o.length}`);
925
}
926
var ptr = rawConstructor();
927
for (var i = 0; i < elementsLength; ++i) {
928
elements[i].write(ptr, o[i]);
929
}
930
if (destructors !== null) {
931
destructors.push(rawDestructor, ptr);
932
}
933
return ptr;
934
},
935
readValueFromPointer: readPointer,
936
destructorFunction: rawDestructor,
937
}];
938
});
939
},
940
941
_embind_register_value_object__deps: [
942
'$structRegistrations', '$AsciiToString', '$embind__requireFunction'],
943
_embind_register_value_object: (
944
rawType,
945
name,
946
constructorSignature,
947
rawConstructor,
948
destructorSignature,
949
rawDestructor
950
) => {
951
structRegistrations[rawType] = {
952
name: AsciiToString(name),
953
rawConstructor: embind__requireFunction(constructorSignature, rawConstructor),
954
rawDestructor: embind__requireFunction(destructorSignature, rawDestructor),
955
fields: [],
956
};
957
},
958
959
_embind_register_value_object_field__deps: [
960
'$structRegistrations', '$AsciiToString', '$embind__requireFunction'],
961
_embind_register_value_object_field: (
962
structType,
963
fieldName,
964
getterReturnType,
965
getterSignature,
966
getter,
967
getterContext,
968
setterArgumentType,
969
setterSignature,
970
setter,
971
setterContext
972
) => {
973
structRegistrations[structType].fields.push({
974
fieldName: AsciiToString(fieldName),
975
getterReturnType,
976
getter: embind__requireFunction(getterSignature, getter),
977
getterContext,
978
setterArgumentType,
979
setter: embind__requireFunction(setterSignature, setter),
980
setterContext,
981
});
982
},
983
984
_embind_finalize_value_object__deps: [
985
'$structRegistrations', '$runDestructors',
986
'$readPointer', '$whenDependentTypesAreResolved'],
987
_embind_finalize_value_object: (structType) => {
988
var reg = structRegistrations[structType];
989
delete structRegistrations[structType];
990
991
var rawConstructor = reg.rawConstructor;
992
var rawDestructor = reg.rawDestructor;
993
var fieldRecords = reg.fields;
994
var fieldTypes = fieldRecords.map((field) => field.getterReturnType).
995
concat(fieldRecords.map((field) => field.setterArgumentType));
996
whenDependentTypesAreResolved([structType], fieldTypes, (fieldTypes) => {
997
var fields = {};
998
fieldRecords.forEach((field, i) => {
999
var fieldName = field.fieldName;
1000
var getterReturnType = fieldTypes[i];
1001
var optional = fieldTypes[i].optional;
1002
var getter = field.getter;
1003
var getterContext = field.getterContext;
1004
var setterArgumentType = fieldTypes[i + fieldRecords.length];
1005
var setter = field.setter;
1006
var setterContext = field.setterContext;
1007
fields[fieldName] = {
1008
read: (ptr) => getterReturnType.fromWireType(getter(getterContext, ptr)),
1009
write: (ptr, o) => {
1010
var destructors = [];
1011
setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o));
1012
runDestructors(destructors);
1013
},
1014
optional,
1015
};
1016
});
1017
1018
return [{
1019
name: reg.name,
1020
fromWireType: (ptr) => {
1021
var rv = {};
1022
for (var i in fields) {
1023
rv[i] = fields[i].read(ptr);
1024
}
1025
rawDestructor(ptr);
1026
return rv;
1027
},
1028
toWireType: (destructors, o) => {
1029
// todo: Here we have an opportunity for -O3 level "unsafe" optimizations:
1030
// assume all fields are present without checking.
1031
for (var fieldName in fields) {
1032
if (!(fieldName in o) && !fields[fieldName].optional) {
1033
throw new TypeError(`Missing field: "${fieldName}"`);
1034
}
1035
}
1036
var ptr = rawConstructor();
1037
for (fieldName in fields) {
1038
fields[fieldName].write(ptr, o[fieldName]);
1039
}
1040
if (destructors !== null) {
1041
destructors.push(rawDestructor, ptr);
1042
}
1043
return ptr;
1044
},
1045
readValueFromPointer: readPointer,
1046
destructorFunction: rawDestructor,
1047
}];
1048
});
1049
},
1050
1051
$genericPointerToWireType__docs: '/** @suppress {globalThis} */',
1052
$genericPointerToWireType__deps: ['$throwBindingError', '$upcastPointer'],
1053
$genericPointerToWireType: function(destructors, handle) {
1054
var ptr;
1055
if (handle === null) {
1056
if (this.isReference) {
1057
throwBindingError(`null is not a valid ${this.name}`);
1058
}
1059
1060
if (this.isSmartPointer) {
1061
ptr = this.rawConstructor();
1062
if (destructors !== null) {
1063
destructors.push(this.rawDestructor, ptr);
1064
}
1065
return ptr;
1066
} else {
1067
return 0;
1068
}
1069
}
1070
1071
if (!handle || !handle.$$) {
1072
throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`);
1073
}
1074
if (!handle.$$.ptr) {
1075
throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`);
1076
}
1077
if (!this.isConst && handle.$$.ptrType.isConst) {
1078
throwBindingError(`Cannot convert argument of type ${(handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name)} to parameter type ${this.name}`);
1079
}
1080
var handleClass = handle.$$.ptrType.registeredClass;
1081
ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass);
1082
1083
if (this.isSmartPointer) {
1084
// TODO: this is not strictly true
1085
// We could support BY_EMVAL conversions from raw pointers to smart pointers
1086
// because the smart pointer can hold a reference to the handle
1087
if (undefined === handle.$$.smartPtr) {
1088
throwBindingError('Passing raw pointer to smart pointer is illegal');
1089
}
1090
1091
switch (this.sharingPolicy) {
1092
case 0: // NONE
1093
// no upcasting
1094
if (handle.$$.smartPtrType === this) {
1095
ptr = handle.$$.smartPtr;
1096
} else {
1097
throwBindingError(`Cannot convert argument of type ${(handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name)} to parameter type ${this.name}`);
1098
}
1099
break;
1100
1101
case 1: // INTRUSIVE
1102
ptr = handle.$$.smartPtr;
1103
break;
1104
1105
case 2: // BY_EMVAL
1106
if (handle.$$.smartPtrType === this) {
1107
ptr = handle.$$.smartPtr;
1108
} else {
1109
var clonedHandle = handle['clone']();
1110
ptr = this.rawShare(
1111
ptr,
1112
Emval.toHandle(() => clonedHandle['delete']())
1113
);
1114
if (destructors !== null) {
1115
destructors.push(this.rawDestructor, ptr);
1116
}
1117
}
1118
break;
1119
1120
default:
1121
throwBindingError('Unsupporting sharing policy');
1122
}
1123
}
1124
return ptr;
1125
},
1126
1127
$constNoSmartPtrRawPointerToWireType__docs: '/** @suppress {globalThis} */',
1128
// If we know a pointer type is not going to have SmartPtr logic in it, we can
1129
// special-case optimize it a bit (compare to genericPointerToWireType)
1130
$constNoSmartPtrRawPointerToWireType__deps: ['$throwBindingError', '$upcastPointer', '$embindRepr'],
1131
$constNoSmartPtrRawPointerToWireType: function(destructors, handle) {
1132
if (handle === null) {
1133
if (this.isReference) {
1134
throwBindingError(`null is not a valid ${this.name}`);
1135
}
1136
return 0;
1137
}
1138
1139
if (!handle.$$) {
1140
throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`);
1141
}
1142
if (!handle.$$.ptr) {
1143
throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`);
1144
}
1145
var handleClass = handle.$$.ptrType.registeredClass;
1146
var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass);
1147
return ptr;
1148
},
1149
1150
$nonConstNoSmartPtrRawPointerToWireType__docs: '/** @suppress {globalThis} */',
1151
// An optimized version for non-const method accesses - there we must additionally restrict that
1152
// the pointer is not a const-pointer.
1153
$nonConstNoSmartPtrRawPointerToWireType__deps: ['$throwBindingError', '$upcastPointer', '$embindRepr'],
1154
$nonConstNoSmartPtrRawPointerToWireType: function(destructors, handle) {
1155
if (handle === null) {
1156
if (this.isReference) {
1157
throwBindingError(`null is not a valid ${this.name}`);
1158
}
1159
return 0;
1160
}
1161
1162
if (!handle.$$) {
1163
throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`);
1164
}
1165
if (!handle.$$.ptr) {
1166
throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`);
1167
}
1168
if (handle.$$.ptrType.isConst) {
1169
throwBindingError(`Cannot convert argument of type ${handle.$$.ptrType.name} to parameter type ${this.name}`);
1170
}
1171
var handleClass = handle.$$.ptrType.registeredClass;
1172
var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass);
1173
return ptr;
1174
},
1175
1176
$init_RegisteredPointer__deps: [
1177
'$RegisteredPointer',
1178
'$readPointer',
1179
'$RegisteredPointer_fromWireType',
1180
],
1181
$init_RegisteredPointer: () => {
1182
Object.assign(RegisteredPointer.prototype, {
1183
getPointee(ptr) {
1184
if (this.rawGetPointee) {
1185
ptr = this.rawGetPointee(ptr);
1186
}
1187
return ptr;
1188
},
1189
destructor(ptr) {
1190
this.rawDestructor?.(ptr);
1191
},
1192
readValueFromPointer: readPointer,
1193
fromWireType: RegisteredPointer_fromWireType,
1194
});
1195
},
1196
1197
$RegisteredPointer__docs: `/** @constructor
1198
@param {*=} pointeeType,
1199
@param {*=} sharingPolicy,
1200
@param {*=} rawGetPointee,
1201
@param {*=} rawConstructor,
1202
@param {*=} rawShare,
1203
@param {*=} rawDestructor,
1204
*/`,
1205
$RegisteredPointer__deps: [
1206
'$constNoSmartPtrRawPointerToWireType', '$genericPointerToWireType',
1207
'$nonConstNoSmartPtrRawPointerToWireType', '$init_RegisteredPointer'],
1208
$RegisteredPointer__postset: 'init_RegisteredPointer()',
1209
$RegisteredPointer: function(
1210
name,
1211
registeredClass,
1212
isReference,
1213
isConst,
1214
1215
// smart pointer properties
1216
isSmartPointer,
1217
pointeeType,
1218
sharingPolicy,
1219
rawGetPointee,
1220
rawConstructor,
1221
rawShare,
1222
rawDestructor
1223
) {
1224
this.name = name;
1225
this.registeredClass = registeredClass;
1226
this.isReference = isReference;
1227
this.isConst = isConst;
1228
1229
// smart pointer properties
1230
this.isSmartPointer = isSmartPointer;
1231
this.pointeeType = pointeeType;
1232
this.sharingPolicy = sharingPolicy;
1233
this.rawGetPointee = rawGetPointee;
1234
this.rawConstructor = rawConstructor;
1235
this.rawShare = rawShare;
1236
this.rawDestructor = rawDestructor;
1237
1238
if (!isSmartPointer && registeredClass.baseClass === undefined) {
1239
if (isConst) {
1240
this.toWireType = constNoSmartPtrRawPointerToWireType;
1241
this.destructorFunction = null;
1242
} else {
1243
this.toWireType = nonConstNoSmartPtrRawPointerToWireType;
1244
this.destructorFunction = null;
1245
}
1246
} else {
1247
this.toWireType = genericPointerToWireType;
1248
// Here we must leave this.destructorFunction undefined, since whether genericPointerToWireType returns
1249
// a pointer that needs to be freed up is runtime-dependent, and cannot be evaluated at registration time.
1250
// TODO: Create an alternative mechanism that allows removing the use of var destructors = []; array in
1251
// craftInvokerFunction altogether.
1252
}
1253
},
1254
1255
$RegisteredPointer_fromWireType__docs: '/** @suppress {globalThis} */',
1256
$RegisteredPointer_fromWireType__deps: [
1257
'$downcastPointer', '$registeredPointers',
1258
'$getInheritedInstance', '$makeClassHandle',
1259
#if MEMORY64
1260
'$bigintToI53Checked'
1261
#endif
1262
],
1263
$RegisteredPointer_fromWireType: function(ptr) {
1264
// ptr is a raw pointer (or a raw smartpointer)
1265
#if MEMORY64
1266
ptr = bigintToI53Checked(ptr);
1267
#if ASSERTIONS
1268
assert(Number.isSafeInteger(ptr));
1269
#endif
1270
#endif
1271
1272
// rawPointer is a maybe-null raw pointer
1273
var rawPointer = this.getPointee(ptr);
1274
if (!rawPointer) {
1275
this.destructor(ptr);
1276
return null;
1277
}
1278
1279
var registeredInstance = getInheritedInstance(this.registeredClass, rawPointer);
1280
if (undefined !== registeredInstance) {
1281
// JS object has been neutered, time to repopulate it
1282
if (0 === registeredInstance.$$.count.value) {
1283
registeredInstance.$$.ptr = rawPointer;
1284
registeredInstance.$$.smartPtr = ptr;
1285
return registeredInstance['clone']();
1286
} else {
1287
// else, just increment reference count on existing object
1288
// it already has a reference to the smart pointer
1289
var rv = registeredInstance['clone']();
1290
this.destructor(ptr);
1291
return rv;
1292
}
1293
}
1294
1295
function makeDefaultHandle() {
1296
if (this.isSmartPointer) {
1297
return makeClassHandle(this.registeredClass.instancePrototype, {
1298
ptrType: this.pointeeType,
1299
ptr: rawPointer,
1300
smartPtrType: this,
1301
smartPtr: ptr,
1302
});
1303
} else {
1304
return makeClassHandle(this.registeredClass.instancePrototype, {
1305
ptrType: this,
1306
ptr,
1307
});
1308
}
1309
}
1310
1311
var actualType = this.registeredClass.getActualType(rawPointer);
1312
var registeredPointerRecord = registeredPointers[actualType];
1313
if (!registeredPointerRecord) {
1314
return makeDefaultHandle.call(this);
1315
}
1316
1317
var toType;
1318
if (this.isConst) {
1319
toType = registeredPointerRecord.constPointerType;
1320
} else {
1321
toType = registeredPointerRecord.pointerType;
1322
}
1323
var dp = downcastPointer(
1324
rawPointer,
1325
this.registeredClass,
1326
toType.registeredClass);
1327
if (dp === null) {
1328
return makeDefaultHandle.call(this);
1329
}
1330
if (this.isSmartPointer) {
1331
return makeClassHandle(toType.registeredClass.instancePrototype, {
1332
ptrType: toType,
1333
ptr: dp,
1334
smartPtrType: this,
1335
smartPtr: ptr,
1336
});
1337
} else {
1338
return makeClassHandle(toType.registeredClass.instancePrototype, {
1339
ptrType: toType,
1340
ptr: dp,
1341
});
1342
}
1343
},
1344
1345
$runDestructor: ($$) => {
1346
if ($$.smartPtr) {
1347
$$.smartPtrType.rawDestructor($$.smartPtr);
1348
} else {
1349
$$.ptrType.registeredClass.rawDestructor($$.ptr);
1350
}
1351
},
1352
1353
$releaseClassHandle__deps: ['$runDestructor'],
1354
$releaseClassHandle: ($$) => {
1355
$$.count.value -= 1;
1356
var toDelete = 0 === $$.count.value;
1357
if (toDelete) {
1358
runDestructor($$);
1359
}
1360
},
1361
1362
$finalizationRegistry: false,
1363
1364
$detachFinalizer_deps: ['$finalizationRegistry'],
1365
$detachFinalizer: (handle) => {},
1366
1367
$attachFinalizer__deps: [
1368
'$finalizationRegistry', '$detachFinalizer', '$releaseClassHandle',
1369
#if ASSERTIONS
1370
'$RegisteredPointer_fromWireType'
1371
#endif
1372
],
1373
$attachFinalizer: (handle) => {
1374
if ('undefined' === typeof FinalizationRegistry) {
1375
attachFinalizer = (handle) => handle;
1376
return handle;
1377
}
1378
// If the running environment has a FinalizationRegistry (see
1379
// https://github.com/tc39/proposal-weakrefs), then attach finalizers
1380
// for class handles. We check for the presence of FinalizationRegistry
1381
// at run-time, not build-time.
1382
finalizationRegistry = new FinalizationRegistry((info) => {
1383
#if ASSERTIONS
1384
console.warn(info.leakWarning);
1385
#endif
1386
releaseClassHandle(info.$$);
1387
});
1388
attachFinalizer = (handle) => {
1389
var $$ = handle.$$;
1390
var hasSmartPtr = !!$$.smartPtr;
1391
if (hasSmartPtr) {
1392
// We should not call the destructor on raw pointers in case other code expects the pointee to live
1393
var info = { $$: $$ };
1394
#if ASSERTIONS
1395
// Create a warning as an Error instance in advance so that we can store
1396
// the current stacktrace and point to it when / if a leak is detected.
1397
// This is more useful than the empty stacktrace of `FinalizationRegistry`
1398
// callback.
1399
var cls = $$.ptrType.registeredClass;
1400
var err = new Error(`Embind found a leaked C++ instance ${cls.name} <${ptrToString($$.ptr)}>.\n` +
1401
"We'll free it automatically in this case, but this functionality is not reliable across various environments.\n" +
1402
"Make sure to invoke .delete() manually once you're done with the instance instead.\n" +
1403
"Originally allocated"); // `.stack` will add "at ..." after this sentence
1404
if ('captureStackTrace' in Error) {
1405
Error.captureStackTrace(err, RegisteredPointer_fromWireType);
1406
}
1407
info.leakWarning = err.stack.replace(/^Error: /, '');
1408
#endif
1409
finalizationRegistry.register(handle, info, handle);
1410
}
1411
return handle;
1412
};
1413
detachFinalizer = (handle) => finalizationRegistry.unregister(handle);
1414
return attachFinalizer(handle);
1415
},
1416
1417
$makeClassHandle__deps: ['$throwInternalError', '$attachFinalizer'],
1418
$makeClassHandle: (prototype, record) => {
1419
if (!record.ptrType || !record.ptr) {
1420
throwInternalError('makeClassHandle requires ptr and ptrType');
1421
}
1422
var hasSmartPtrType = !!record.smartPtrType;
1423
var hasSmartPtr = !!record.smartPtr;
1424
if (hasSmartPtrType !== hasSmartPtr) {
1425
throwInternalError('Both smartPtrType and smartPtr must be specified');
1426
}
1427
record.count = { value: 1 };
1428
return attachFinalizer(Object.create(prototype, {
1429
$$: {
1430
value: record,
1431
writable: true,
1432
},
1433
}));
1434
},
1435
1436
$init_ClassHandle__deps: [
1437
'$ClassHandle',
1438
'$shallowCopyInternalPointer',
1439
'$throwInstanceAlreadyDeleted',
1440
'$attachFinalizer',
1441
'$releaseClassHandle',
1442
'$throwBindingError',
1443
'$detachFinalizer',
1444
'$flushPendingDeletes',
1445
'$delayFunction',
1446
],
1447
$init_ClassHandle: () => {
1448
let proto = ClassHandle.prototype;
1449
1450
Object.assign(proto, {
1451
"isAliasOf"(other) {
1452
if (!(this instanceof ClassHandle)) {
1453
return false;
1454
}
1455
if (!(other instanceof ClassHandle)) {
1456
return false;
1457
}
1458
1459
var leftClass = this.$$.ptrType.registeredClass;
1460
var left = this.$$.ptr;
1461
other.$$ = /** @type {Object} */ (other.$$);
1462
var rightClass = other.$$.ptrType.registeredClass;
1463
var right = other.$$.ptr;
1464
1465
while (leftClass.baseClass) {
1466
left = leftClass.upcast(left);
1467
leftClass = leftClass.baseClass;
1468
}
1469
1470
while (rightClass.baseClass) {
1471
right = rightClass.upcast(right);
1472
rightClass = rightClass.baseClass;
1473
}
1474
1475
return leftClass === rightClass && left === right;
1476
},
1477
1478
"clone"() {
1479
if (!this.$$.ptr) {
1480
throwInstanceAlreadyDeleted(this);
1481
}
1482
1483
if (this.$$.preservePointerOnDelete) {
1484
this.$$.count.value += 1;
1485
return this;
1486
} else {
1487
var clone = attachFinalizer(Object.create(Object.getPrototypeOf(this), {
1488
$$: {
1489
value: shallowCopyInternalPointer(this.$$),
1490
}
1491
}));
1492
1493
clone.$$.count.value += 1;
1494
clone.$$.deleteScheduled = false;
1495
return clone;
1496
}
1497
},
1498
1499
"delete"() {
1500
if (!this.$$.ptr) {
1501
throwInstanceAlreadyDeleted(this);
1502
}
1503
1504
if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) {
1505
throwBindingError('Object already scheduled for deletion');
1506
}
1507
1508
detachFinalizer(this);
1509
releaseClassHandle(this.$$);
1510
1511
if (!this.$$.preservePointerOnDelete) {
1512
this.$$.smartPtr = undefined;
1513
this.$$.ptr = undefined;
1514
}
1515
},
1516
1517
"isDeleted"() {
1518
return !this.$$.ptr;
1519
},
1520
1521
"deleteLater"() {
1522
if (!this.$$.ptr) {
1523
throwInstanceAlreadyDeleted(this);
1524
}
1525
if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) {
1526
throwBindingError('Object already scheduled for deletion');
1527
}
1528
deletionQueue.push(this);
1529
if (deletionQueue.length === 1 && delayFunction) {
1530
delayFunction(flushPendingDeletes);
1531
}
1532
this.$$.deleteScheduled = true;
1533
return this;
1534
},
1535
});
1536
1537
// Support `using ...` from https://github.com/tc39/proposal-explicit-resource-management.
1538
const symbolDispose = Symbol.dispose;
1539
if (symbolDispose) {
1540
proto[symbolDispose] = proto['delete'];
1541
}
1542
},
1543
1544
$ClassHandle__docs: '/** @constructor */',
1545
$ClassHandle__deps: ['$init_ClassHandle'],
1546
$ClassHandle__postset: 'init_ClassHandle()',
1547
// root of all pointer and smart pointer handles in embind
1548
$ClassHandle: function() {
1549
},
1550
1551
$throwInstanceAlreadyDeleted__deps: ['$throwBindingError'],
1552
$throwInstanceAlreadyDeleted: (obj) => {
1553
function getInstanceTypeName(handle) {
1554
return handle.$$.ptrType.registeredClass.name;
1555
}
1556
throwBindingError(getInstanceTypeName(obj) + ' instance already deleted');
1557
},
1558
1559
$deletionQueue: [],
1560
1561
$flushPendingDeletes__deps: ['$deletionQueue'],
1562
$flushPendingDeletes: () => {
1563
while (deletionQueue.length) {
1564
var obj = deletionQueue.pop();
1565
obj.$$.deleteScheduled = false;
1566
obj['delete']();
1567
}
1568
},
1569
1570
$delayFunction: undefined,
1571
1572
$setDelayFunction__deps: ['$delayFunction', '$deletionQueue', '$flushPendingDeletes'],
1573
$setDelayFunction: (fn) => {
1574
delayFunction = fn;
1575
if (deletionQueue.length && delayFunction) {
1576
delayFunction(flushPendingDeletes);
1577
}
1578
},
1579
1580
$RegisteredClass__docs: '/** @constructor */',
1581
$RegisteredClass: function(name,
1582
constructor,
1583
instancePrototype,
1584
rawDestructor,
1585
baseClass,
1586
getActualType,
1587
upcast,
1588
downcast) {
1589
this.name = name;
1590
this.constructor = constructor;
1591
this.instancePrototype = instancePrototype;
1592
this.rawDestructor = rawDestructor;
1593
this.baseClass = baseClass;
1594
this.getActualType = getActualType;
1595
this.upcast = upcast;
1596
this.downcast = downcast;
1597
this.pureVirtualFunctions = [];
1598
},
1599
1600
$shallowCopyInternalPointer: (o) => {
1601
return {
1602
count: o.count,
1603
deleteScheduled: o.deleteScheduled,
1604
preservePointerOnDelete: o.preservePointerOnDelete,
1605
ptr: o.ptr,
1606
ptrType: o.ptrType,
1607
smartPtr: o.smartPtr,
1608
smartPtrType: o.smartPtrType,
1609
};
1610
},
1611
1612
_embind_register_class__deps: [
1613
'$BindingError', '$ClassHandle', '$createNamedFunction',
1614
'$registeredPointers', '$exposePublicSymbol',
1615
'$makeLegalFunctionName', '$AsciiToString',
1616
'$RegisteredClass', '$RegisteredPointer', '$replacePublicSymbol',
1617
'$embind__requireFunction', '$throwUnboundTypeError',
1618
'$whenDependentTypesAreResolved'],
1619
_embind_register_class: (rawType,
1620
rawPointerType,
1621
rawConstPointerType,
1622
baseClassRawType,
1623
getActualTypeSignature,
1624
getActualType,
1625
upcastSignature,
1626
upcast,
1627
downcastSignature,
1628
downcast,
1629
name,
1630
destructorSignature,
1631
rawDestructor) => {
1632
name = AsciiToString(name);
1633
getActualType = embind__requireFunction(getActualTypeSignature, getActualType);
1634
upcast &&= embind__requireFunction(upcastSignature, upcast);
1635
downcast &&= embind__requireFunction(downcastSignature, downcast);
1636
rawDestructor = embind__requireFunction(destructorSignature, rawDestructor);
1637
var legalFunctionName = makeLegalFunctionName(name);
1638
1639
exposePublicSymbol(legalFunctionName, function() {
1640
// this code cannot run if baseClassRawType is zero
1641
throwUnboundTypeError(`Cannot construct ${name} due to unbound types`, [baseClassRawType]);
1642
});
1643
1644
whenDependentTypesAreResolved(
1645
[rawType, rawPointerType, rawConstPointerType],
1646
baseClassRawType ? [baseClassRawType] : [],
1647
(base) => {
1648
base = base[0];
1649
1650
var baseClass;
1651
var basePrototype;
1652
if (baseClassRawType) {
1653
baseClass = base.registeredClass;
1654
basePrototype = baseClass.instancePrototype;
1655
} else {
1656
basePrototype = ClassHandle.prototype;
1657
}
1658
1659
var constructor = createNamedFunction(name, function(...args) {
1660
if (Object.getPrototypeOf(this) !== instancePrototype) {
1661
throw new BindingError(`Use 'new' to construct ${name}`);
1662
}
1663
if (undefined === registeredClass.constructor_body) {
1664
throw new BindingError(`${name} has no accessible constructor`);
1665
}
1666
var body = registeredClass.constructor_body[args.length];
1667
if (undefined === body) {
1668
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!`);
1669
}
1670
return body.apply(this, args);
1671
});
1672
1673
var instancePrototype = Object.create(basePrototype, {
1674
constructor: { value: constructor },
1675
});
1676
1677
constructor.prototype = instancePrototype;
1678
1679
var registeredClass = new RegisteredClass(name,
1680
constructor,
1681
instancePrototype,
1682
rawDestructor,
1683
baseClass,
1684
getActualType,
1685
upcast,
1686
downcast);
1687
1688
if (registeredClass.baseClass) {
1689
// Keep track of class hierarchy. Used to allow sub-classes to inherit class functions.
1690
registeredClass.baseClass.__derivedClasses ??= [];
1691
1692
registeredClass.baseClass.__derivedClasses.push(registeredClass);
1693
}
1694
1695
var referenceConverter = new RegisteredPointer(name,
1696
registeredClass,
1697
true,
1698
false,
1699
false);
1700
1701
var pointerConverter = new RegisteredPointer(name + '*',
1702
registeredClass,
1703
false,
1704
false,
1705
false);
1706
1707
var constPointerConverter = new RegisteredPointer(name + ' const*',
1708
registeredClass,
1709
false,
1710
true,
1711
false);
1712
1713
registeredPointers[rawType] = {
1714
pointerType: pointerConverter,
1715
constPointerType: constPointerConverter
1716
};
1717
1718
replacePublicSymbol(legalFunctionName, constructor);
1719
1720
return [referenceConverter, pointerConverter, constPointerConverter];
1721
}
1722
);
1723
},
1724
1725
_embind_register_class_constructor__deps: [
1726
'$heap32VectorToArray', '$embind__requireFunction',
1727
'$whenDependentTypesAreResolved',
1728
'$craftInvokerFunction'],
1729
_embind_register_class_constructor: (
1730
rawClassType,
1731
argCount,
1732
rawArgTypesAddr,
1733
invokerSignature,
1734
invoker,
1735
rawConstructor
1736
) => {
1737
#if ASSERTIONS
1738
assert(argCount > 0);
1739
#endif
1740
var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
1741
invoker = embind__requireFunction(invokerSignature, invoker);
1742
var args = [rawConstructor];
1743
var destructors = [];
1744
1745
whenDependentTypesAreResolved([], [rawClassType], (classType) => {
1746
classType = classType[0];
1747
var humanName = `constructor ${classType.name}`;
1748
1749
if (undefined === classType.registeredClass.constructor_body) {
1750
classType.registeredClass.constructor_body = [];
1751
}
1752
if (undefined !== classType.registeredClass.constructor_body[argCount - 1]) {
1753
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!`);
1754
}
1755
classType.registeredClass.constructor_body[argCount - 1] = () => {
1756
throwUnboundTypeError(`Cannot construct ${classType.name} due to unbound types`, rawArgTypes);
1757
};
1758
1759
whenDependentTypesAreResolved([], rawArgTypes, (argTypes) => {
1760
// Insert empty slot for context type (argTypes[1]).
1761
argTypes.splice(1, 0, null);
1762
classType.registeredClass.constructor_body[argCount - 1] = craftInvokerFunction(humanName, argTypes, null, invoker, rawConstructor);
1763
return [];
1764
});
1765
return [];
1766
});
1767
},
1768
1769
$downcastPointer: (ptr, ptrClass, desiredClass) => {
1770
if (ptrClass === desiredClass) {
1771
return ptr;
1772
}
1773
if (undefined === desiredClass.baseClass) {
1774
return null; // no conversion
1775
}
1776
1777
var rv = downcastPointer(ptr, ptrClass, desiredClass.baseClass);
1778
if (rv === null) {
1779
return null;
1780
}
1781
return desiredClass.downcast(rv);
1782
},
1783
1784
$upcastPointer__deps: ['$throwBindingError'],
1785
$upcastPointer: (ptr, ptrClass, desiredClass) => {
1786
while (ptrClass !== desiredClass) {
1787
if (!ptrClass.upcast) {
1788
throwBindingError(`Expected null or instance of ${desiredClass.name}, got an instance of ${ptrClass.name}`);
1789
}
1790
ptr = ptrClass.upcast(ptr);
1791
ptrClass = ptrClass.baseClass;
1792
}
1793
return ptr;
1794
},
1795
1796
$validateThis__deps: ['$throwBindingError', '$upcastPointer'],
1797
$validateThis: (this_, classType, humanName) => {
1798
if (!(this_ instanceof Object)) {
1799
throwBindingError(`${humanName} with invalid "this": ${this_}`);
1800
}
1801
if (!(this_ instanceof classType.registeredClass.constructor)) {
1802
throwBindingError(`${humanName} incompatible with "this" of type ${this_.constructor.name}`);
1803
}
1804
if (!this_.$$.ptr) {
1805
throwBindingError(`cannot call emscripten binding method ${humanName} on deleted object`);
1806
}
1807
1808
// todo: kill this
1809
return upcastPointer(this_.$$.ptr,
1810
this_.$$.ptrType.registeredClass,
1811
classType.registeredClass);
1812
},
1813
1814
_embind_register_class_function__deps: [
1815
'$craftInvokerFunction', '$heap32VectorToArray', '$AsciiToString',
1816
'$embind__requireFunction', '$throwUnboundTypeError',
1817
'$whenDependentTypesAreResolved', '$getFunctionName'],
1818
_embind_register_class_function: (rawClassType,
1819
methodName,
1820
argCount,
1821
rawArgTypesAddr, // [ReturnType, ThisType, Args...]
1822
invokerSignature,
1823
rawInvoker,
1824
context,
1825
isPureVirtual,
1826
isAsync,
1827
isNonnullReturn) => {
1828
var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
1829
methodName = AsciiToString(methodName);
1830
methodName = getFunctionName(methodName);
1831
rawInvoker = embind__requireFunction(invokerSignature, rawInvoker, isAsync);
1832
1833
whenDependentTypesAreResolved([], [rawClassType], (classType) => {
1834
classType = classType[0];
1835
var humanName = `${classType.name}.${methodName}`;
1836
1837
if (methodName.startsWith("@@")) {
1838
methodName = Symbol[methodName.substring(2)];
1839
}
1840
1841
if (isPureVirtual) {
1842
classType.registeredClass.pureVirtualFunctions.push(methodName);
1843
}
1844
1845
function unboundTypesHandler() {
1846
throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`, rawArgTypes);
1847
}
1848
1849
var proto = classType.registeredClass.instancePrototype;
1850
var method = proto[methodName];
1851
if (undefined === method || (undefined === method.overloadTable && method.className !== classType.name && method.argCount === argCount - 2)) {
1852
// This is the first overload to be registered, OR we are replacing a
1853
// function in the base class with a function in the derived class.
1854
unboundTypesHandler.argCount = argCount - 2;
1855
unboundTypesHandler.className = classType.name;
1856
proto[methodName] = unboundTypesHandler;
1857
} else {
1858
// There was an existing function with the same name registered. Set up
1859
// a function overload routing table.
1860
ensureOverloadTable(proto, methodName, humanName);
1861
proto[methodName].overloadTable[argCount - 2] = unboundTypesHandler;
1862
}
1863
1864
whenDependentTypesAreResolved([], rawArgTypes, (argTypes) => {
1865
var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context, isAsync);
1866
1867
// Replace the initial unbound-handler-stub function with the
1868
// appropriate member function, now that all types are resolved. If
1869
// multiple overloads are registered for this function, the function
1870
// goes into an overload table.
1871
if (undefined === proto[methodName].overloadTable) {
1872
// Set argCount in case an overload is registered later
1873
memberFunction.argCount = argCount - 2;
1874
proto[methodName] = memberFunction;
1875
} else {
1876
proto[methodName].overloadTable[argCount - 2] = memberFunction;
1877
}
1878
1879
return [];
1880
});
1881
return [];
1882
});
1883
},
1884
1885
_embind_register_class_property__deps: [
1886
'$AsciiToString', '$embind__requireFunction', '$runDestructors',
1887
'$throwBindingError', '$throwUnboundTypeError',
1888
'$whenDependentTypesAreResolved', '$validateThis'],
1889
_embind_register_class_property: (classType,
1890
fieldName,
1891
getterReturnType,
1892
getterSignature,
1893
getter,
1894
getterContext,
1895
setterArgumentType,
1896
setterSignature,
1897
setter,
1898
setterContext) => {
1899
fieldName = AsciiToString(fieldName);
1900
getter = embind__requireFunction(getterSignature, getter);
1901
1902
whenDependentTypesAreResolved([], [classType], (classType) => {
1903
classType = classType[0];
1904
var humanName = `${classType.name}.${fieldName}`;
1905
var desc = {
1906
get() {
1907
throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [getterReturnType, setterArgumentType]);
1908
},
1909
enumerable: true,
1910
configurable: true
1911
};
1912
if (setter) {
1913
desc.set = () => throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [getterReturnType, setterArgumentType]);
1914
} else {
1915
desc.set = (v) => throwBindingError(humanName + ' is a read-only property');
1916
}
1917
1918
Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, desc);
1919
1920
whenDependentTypesAreResolved(
1921
[],
1922
(setter ? [getterReturnType, setterArgumentType] : [getterReturnType]),
1923
(types) => {
1924
var getterReturnType = types[0];
1925
var desc = {
1926
get() {
1927
var ptr = validateThis(this, classType, humanName + ' getter');
1928
return getterReturnType.fromWireType(getter(getterContext, ptr));
1929
},
1930
enumerable: true
1931
};
1932
1933
if (setter) {
1934
setter = embind__requireFunction(setterSignature, setter);
1935
var setterArgumentType = types[1];
1936
desc.set = function(v) {
1937
var ptr = validateThis(this, classType, humanName + ' setter');
1938
var destructors = [];
1939
setter(setterContext, ptr, setterArgumentType.toWireType(destructors, v));
1940
runDestructors(destructors);
1941
};
1942
}
1943
1944
Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, desc);
1945
return [];
1946
});
1947
1948
return [];
1949
});
1950
},
1951
1952
_embind_register_class_class_function__deps: [
1953
'$craftInvokerFunction', '$ensureOverloadTable', '$heap32VectorToArray',
1954
'$AsciiToString', '$embind__requireFunction', '$throwUnboundTypeError',
1955
'$whenDependentTypesAreResolved', '$getFunctionName'],
1956
_embind_register_class_class_function: (rawClassType,
1957
methodName,
1958
argCount,
1959
rawArgTypesAddr,
1960
invokerSignature,
1961
rawInvoker,
1962
fn,
1963
isAsync,
1964
isNonnullReturn) => {
1965
var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
1966
methodName = AsciiToString(methodName);
1967
methodName = getFunctionName(methodName);
1968
rawInvoker = embind__requireFunction(invokerSignature, rawInvoker, isAsync);
1969
whenDependentTypesAreResolved([], [rawClassType], (classType) => {
1970
classType = classType[0];
1971
var humanName = `${classType.name}.${methodName}`;
1972
1973
function unboundTypesHandler() {
1974
throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`, rawArgTypes);
1975
}
1976
1977
if (methodName.startsWith('@@')) {
1978
methodName = Symbol[methodName.substring(2)];
1979
}
1980
1981
var proto = classType.registeredClass.constructor;
1982
if (undefined === proto[methodName]) {
1983
// This is the first function to be registered with this name.
1984
unboundTypesHandler.argCount = argCount-1;
1985
proto[methodName] = unboundTypesHandler;
1986
} else {
1987
// There was an existing function with the same name registered. Set up
1988
// a function overload routing table.
1989
ensureOverloadTable(proto, methodName, humanName);
1990
proto[methodName].overloadTable[argCount-1] = unboundTypesHandler;
1991
}
1992
1993
whenDependentTypesAreResolved([], rawArgTypes, (argTypes) => {
1994
// Replace the initial unbound-types-handler stub with the proper
1995
// function. If multiple overloads are registered, the function handlers
1996
// go into an overload table.
1997
var invokerArgsArray = [argTypes[0] /* return value */, null /* no class 'this'*/].concat(argTypes.slice(1) /* actual params */);
1998
var func = craftInvokerFunction(humanName, invokerArgsArray, null /* no class 'this'*/, rawInvoker, fn, isAsync);
1999
if (undefined === proto[methodName].overloadTable) {
2000
func.argCount = argCount-1;
2001
proto[methodName] = func;
2002
} else {
2003
proto[methodName].overloadTable[argCount-1] = func;
2004
}
2005
2006
if (classType.registeredClass.__derivedClasses) {
2007
for (const derivedClass of classType.registeredClass.__derivedClasses) {
2008
if (!derivedClass.constructor.hasOwnProperty(methodName)) {
2009
// TODO: Add support for overloads
2010
derivedClass.constructor[methodName] = func;
2011
}
2012
}
2013
}
2014
2015
return [];
2016
});
2017
return [];
2018
});
2019
},
2020
2021
_embind_register_class_class_property__deps: [
2022
'$AsciiToString', '$embind__requireFunction', '$runDestructors',
2023
'$throwBindingError', '$throwUnboundTypeError',
2024
'$whenDependentTypesAreResolved'],
2025
_embind_register_class_class_property: (rawClassType,
2026
fieldName,
2027
rawFieldType,
2028
rawFieldPtr,
2029
getterSignature,
2030
getter,
2031
setterSignature,
2032
setter) => {
2033
fieldName = AsciiToString(fieldName);
2034
getter = embind__requireFunction(getterSignature, getter);
2035
2036
whenDependentTypesAreResolved([], [rawClassType], (classType) => {
2037
classType = classType[0];
2038
var humanName = `${classType.name}.${fieldName}`;
2039
var desc = {
2040
get() {
2041
throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [rawFieldType]);
2042
},
2043
enumerable: true,
2044
configurable: true
2045
};
2046
if (setter) {
2047
desc.set = () => {
2048
throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [rawFieldType]);
2049
};
2050
} else {
2051
desc.set = (v) => {
2052
throwBindingError(`${humanName} is a read-only property`);
2053
};
2054
}
2055
2056
Object.defineProperty(classType.registeredClass.constructor, fieldName, desc);
2057
2058
whenDependentTypesAreResolved([], [rawFieldType], (fieldType) => {
2059
fieldType = fieldType[0];
2060
var desc = {
2061
get() {
2062
return fieldType.fromWireType(getter(rawFieldPtr));
2063
},
2064
enumerable: true
2065
};
2066
2067
if (setter) {
2068
setter = embind__requireFunction(setterSignature, setter);
2069
desc.set = (v) => {
2070
var destructors = [];
2071
setter(rawFieldPtr, fieldType.toWireType(destructors, v));
2072
runDestructors(destructors);
2073
};
2074
}
2075
2076
Object.defineProperty(classType.registeredClass.constructor, fieldName, desc);
2077
return [];
2078
});
2079
2080
return [];
2081
});
2082
},
2083
2084
_embind_create_inheriting_constructor__deps: [
2085
'$createNamedFunction', '$Emval',
2086
'$PureVirtualError', '$AsciiToString',
2087
'$registerInheritedInstance',
2088
'$requireRegisteredType', '$throwBindingError',
2089
'$unregisterInheritedInstance', '$detachFinalizer', '$attachFinalizer'],
2090
_embind_create_inheriting_constructor: (constructorName, wrapperType, properties) => {
2091
constructorName = AsciiToString(constructorName);
2092
wrapperType = requireRegisteredType(wrapperType, 'wrapper');
2093
properties = Emval.toValue(properties);
2094
2095
var registeredClass = wrapperType.registeredClass;
2096
var wrapperPrototype = registeredClass.instancePrototype;
2097
var baseClass = registeredClass.baseClass;
2098
var baseClassPrototype = baseClass.instancePrototype;
2099
var baseConstructor = registeredClass.baseClass.constructor;
2100
var ctor = createNamedFunction(constructorName, function(...args) {
2101
registeredClass.baseClass.pureVirtualFunctions.forEach(function(name) {
2102
if (this[name] === baseClassPrototype[name]) {
2103
throw new PureVirtualError(`Pure virtual function ${name} must be implemented in JavaScript`);
2104
}
2105
}.bind(this));
2106
2107
Object.defineProperty(this, '__parent', {
2108
value: wrapperPrototype
2109
});
2110
this['__construct'](...args);
2111
});
2112
2113
// It's a little nasty that we're modifying the wrapper prototype here.
2114
2115
wrapperPrototype['__construct'] = function __construct(...args) {
2116
if (this === wrapperPrototype) {
2117
throwBindingError("Pass correct 'this' to __construct");
2118
}
2119
2120
var inner = baseConstructor['implement'](this, ...args);
2121
detachFinalizer(inner);
2122
var $$ = inner.$$;
2123
inner['notifyOnDestruction']();
2124
$$.preservePointerOnDelete = true;
2125
Object.defineProperties(this, { $$: {
2126
value: $$
2127
}});
2128
attachFinalizer(this);
2129
registerInheritedInstance(registeredClass, $$.ptr, this);
2130
};
2131
2132
wrapperPrototype['__destruct'] = function __destruct() {
2133
if (this === wrapperPrototype) {
2134
throwBindingError("Pass correct 'this' to __destruct");
2135
}
2136
2137
detachFinalizer(this);
2138
unregisterInheritedInstance(registeredClass, this.$$.ptr);
2139
};
2140
2141
ctor.prototype = Object.create(wrapperPrototype);
2142
Object.assign(ctor.prototype, properties);
2143
return Emval.toHandle(ctor);
2144
},
2145
2146
$char_0: '0'.charCodeAt(0),
2147
$char_9: '9'.charCodeAt(0),
2148
$makeLegalFunctionName__deps: ['$char_0', '$char_9'],
2149
$makeLegalFunctionName: (name) => {
2150
#if ASSERTIONS
2151
assert(typeof name === 'string');
2152
#endif
2153
name = name.replace(/[^a-zA-Z0-9_]/g, '$');
2154
var f = name.charCodeAt(0);
2155
if (f >= char_0 && f <= char_9) {
2156
return `_${name}`;
2157
}
2158
return name;
2159
},
2160
2161
_embind_register_smart_ptr__deps: ['$RegisteredPointer', '$embind__requireFunction', '$whenDependentTypesAreResolved'],
2162
_embind_register_smart_ptr: (rawType,
2163
rawPointeeType,
2164
name,
2165
sharingPolicy,
2166
getPointeeSignature,
2167
rawGetPointee,
2168
constructorSignature,
2169
rawConstructor,
2170
shareSignature,
2171
rawShare,
2172
destructorSignature,
2173
rawDestructor) => {
2174
name = AsciiToString(name);
2175
rawGetPointee = embind__requireFunction(getPointeeSignature, rawGetPointee);
2176
rawConstructor = embind__requireFunction(constructorSignature, rawConstructor);
2177
rawShare = embind__requireFunction(shareSignature, rawShare);
2178
rawDestructor = embind__requireFunction(destructorSignature, rawDestructor);
2179
2180
whenDependentTypesAreResolved([rawType], [rawPointeeType], (pointeeType) => {
2181
pointeeType = pointeeType[0];
2182
2183
var registeredPointer = new RegisteredPointer(name,
2184
pointeeType.registeredClass,
2185
false,
2186
false,
2187
// smart pointer properties
2188
true,
2189
pointeeType,
2190
sharingPolicy,
2191
rawGetPointee,
2192
rawConstructor,
2193
rawShare,
2194
rawDestructor);
2195
return [registeredPointer];
2196
});
2197
},
2198
2199
_embind_register_enum__docs: '/** @suppress {globalThis} */',
2200
_embind_register_enum__deps: ['$exposePublicSymbol', '$enumReadValueFromPointer',
2201
'$AsciiToString', '$registerType'],
2202
_embind_register_enum: (rawType, name, size, isSigned) => {
2203
name = AsciiToString(name);
2204
2205
function ctor() {}
2206
ctor.values = {};
2207
2208
registerType(rawType, {
2209
name,
2210
constructor: ctor,
2211
fromWireType: function(c) {
2212
return this.constructor.values[c];
2213
},
2214
toWireType: (destructors, c) => c.value,
2215
readValueFromPointer: enumReadValueFromPointer(name, size, isSigned),
2216
destructorFunction: null,
2217
});
2218
exposePublicSymbol(name, ctor);
2219
},
2220
2221
_embind_register_enum_value__deps: ['$createNamedFunction', '$AsciiToString', '$requireRegisteredType'],
2222
_embind_register_enum_value: (rawEnumType, name, enumValue) => {
2223
var enumType = requireRegisteredType(rawEnumType, 'enum');
2224
name = AsciiToString(name);
2225
2226
var Enum = enumType.constructor;
2227
2228
var Value = Object.create(enumType.constructor.prototype, {
2229
value: {value: enumValue},
2230
constructor: {value: createNamedFunction(`${enumType.name}_${name}`, function() {})},
2231
});
2232
Enum.values[enumValue] = Value;
2233
Enum[name] = Value;
2234
},
2235
2236
_embind_register_constant__deps: ['$AsciiToString', '$whenDependentTypesAreResolved'],
2237
_embind_register_constant: (name, type, value) => {
2238
name = AsciiToString(name);
2239
whenDependentTypesAreResolved([], [type], (type) => {
2240
type = type[0];
2241
Module[name] = type.fromWireType(value);
2242
return [];
2243
});
2244
},
2245
};
2246
2247
addToLibrary(LibraryEmbind);
2248
2249