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