|
17 | 17 | /*global typeDependencies, flushPendingDeletes, getTypeName, getBasestPointer, throwBindingError, UnboundTypeError, _embind_repr, registeredInstances, registeredTypes, getShiftFromSize*/
|
18 | 18 | /*global ensureOverloadTable, embind__requireFunction, awaitingDependencies, makeLegalFunctionName, embind_charCodes:true, registerType, createNamedFunction, RegisteredPointer, throwInternalError*/
|
19 | 19 | /*global simpleReadValueFromPointer, floatReadValueFromPointer, integerReadValueFromPointer, enumReadValueFromPointer, replacePublicSymbol, craftInvokerFunction, tupleRegistrations*/
|
20 |
| -/*global finalizationGroup, attachFinalizer, detachFinalizer, releaseClassHandle, runDestructor*/ |
| 20 | +/*global finalizationRegistry, attachFinalizer, detachFinalizer, releaseClassHandle, runDestructor*/ |
21 | 21 | /*global ClassHandle, makeClassHandle, structRegistrations, whenDependentTypesAreResolved, BindingError, deletionQueue, delayFunction:true, upcastPointer*/
|
22 | 22 | /*global exposePublicSymbol, heap32VectorToArray, new_, RegisteredPointer_getPointee, RegisteredPointer_destructor, RegisteredPointer_deleteObject, char_0, char_9*/
|
23 | 23 | /*global getInheritedInstanceCount, getLiveInheritedInstances, setDelayFunction, InternalError, runDestructors*/
|
@@ -1734,39 +1734,53 @@ var LibraryEmbind = {
|
1734 | 1734 | }
|
1735 | 1735 | },
|
1736 | 1736 |
|
1737 |
| - $finalizationGroup: false, |
| 1737 | + $finalizationRegistry: false, |
1738 | 1738 |
|
1739 |
| - $detachFinalizer_deps: ['$finalizationGroup'], |
| 1739 | + $detachFinalizer_deps: ['$finalizationRegistry'], |
1740 | 1740 | $detachFinalizer: function(handle) {},
|
1741 | 1741 |
|
1742 |
| - $attachFinalizer__deps: ['$finalizationGroup', '$detachFinalizer', |
1743 |
| - '$releaseClassHandle'], |
| 1742 | + $attachFinalizer__deps: ['$finalizationRegistry', '$detachFinalizer', |
| 1743 | + '$releaseClassHandle', '$RegisteredPointer_fromWireType'], |
1744 | 1744 | $attachFinalizer: function(handle) {
|
1745 |
| - if ('undefined' === typeof FinalizationGroup) { |
| 1745 | + if ('undefined' === typeof FinalizationRegistry) { |
1746 | 1746 | attachFinalizer = (handle) => handle;
|
1747 | 1747 | return handle;
|
1748 | 1748 | }
|
1749 |
| - // If the running environment has a FinalizationGroup (see |
| 1749 | + // If the running environment has a FinalizationRegistry (see |
1750 | 1750 | // https://github.com/tc39/proposal-weakrefs), then attach finalizers
|
1751 |
| - // for class handles. We check for the presence of FinalizationGroup |
| 1751 | + // for class handles. We check for the presence of FinalizationRegistry |
1752 | 1752 | // at run-time, not build-time.
|
1753 |
| - finalizationGroup = new FinalizationGroup(function (iter) { |
1754 |
| - for (var result = iter.next(); !result.done; result = iter.next()) { |
1755 |
| - var $$ = result.value; |
1756 |
| - if (!$$.ptr) { |
1757 |
| - console.warn('object already deleted: ' + $$.ptr); |
1758 |
| - } else { |
1759 |
| - releaseClassHandle($$); |
1760 |
| - } |
1761 |
| - } |
| 1753 | + finalizationRegistry = new FinalizationRegistry((info) => { |
| 1754 | +#if ASSERTIONS |
| 1755 | + console.warn(info.leakWarning.stack.replace(/^Error: /, '')); |
| 1756 | +#endif |
| 1757 | + releaseClassHandle(info.$$); |
1762 | 1758 | });
|
1763 | 1759 | attachFinalizer = (handle) => {
|
1764 |
| - finalizationGroup.register(handle, handle.$$, handle.$$); |
| 1760 | + var $$ = handle.$$; |
| 1761 | + var hasSmartPtr = !!$$.smartPtr; |
| 1762 | + if (hasSmartPtr) { |
| 1763 | + // We should not call the destructor on raw pointers in case other code expects the pointee to live |
| 1764 | + var info = { $$: $$ }; |
| 1765 | +#if ASSERTIONS |
| 1766 | + // Create a warning as an Error instance in advance so that we can store |
| 1767 | + // the current stacktrace and point to it when / if a leak is detected. |
| 1768 | + // This is more useful than the empty stacktrace of `FinalizationRegistry` |
| 1769 | + // callback. |
| 1770 | + var cls = $$.ptrType.registeredClass; |
| 1771 | + info.leakWarning = new Error("Embind found a leaked C++ instance " + cls.name + " <0x" + $$.ptr.toString(16) + ">.\n" + |
| 1772 | + "We'll free it automatically in this case, but this functionality is not reliable across various environments.\n" + |
| 1773 | + "Make sure to invoke .delete() manually once you're done with the instance instead.\n" + |
| 1774 | + "Originally allocated"); // `.stack` will add "at ..." after this sentence |
| 1775 | + if ('captureStackTrace' in Error) { |
| 1776 | + Error.captureStackTrace(info.leakWarning, RegisteredPointer_fromWireType); |
| 1777 | + } |
| 1778 | + #endif |
| 1779 | + finalizationRegistry.register(handle, info, handle); |
| 1780 | + } |
1765 | 1781 | return handle;
|
1766 | 1782 | };
|
1767 |
| - detachFinalizer = (handle) => { |
1768 |
| - finalizationGroup.unregister(handle.$$); |
1769 |
| - }; |
| 1783 | + detachFinalizer = (handle) => finalizationRegistry.unregister(handle); |
1770 | 1784 | return attachFinalizer(handle);
|
1771 | 1785 | },
|
1772 | 1786 |
|
|
0 commit comments