src: avoid making JSTransferable wrapper object weak#50026
src: avoid making JSTransferable wrapper object weak#50026nodejs-github-bot merged 1 commit intonodejs:mainfrom
Conversation
JSTransferable wrapper object is a short-lived wrapper in the scope of the serialization or the deserialization. Make the JSTransferable wrapper object pointer as a strongly-referenced detached BaseObjectPtr so that a JSTransferable wrapper object and its target object will never be garbage-collected during a ser-des process, and the wrapper object will be immediately destroyed when the process is completed.
| } | ||
|
|
||
| JSTransferable::~JSTransferable() { | ||
| HandleScope scope(env()->isolate()); |
There was a problem hiding this comment.
For education purposes: What is the purpose of initializing a scope in here?
There was a problem hiding this comment.
A local handle is created with target_.Get(env()->isolate()) in the next line. A handle scope is needed in place to collect the local handle when it goes out of lexical scope.
|
The crash still occurs even with this commit: |
|
Stress test: https://ci.nodejs.org/job/node-stress-single-test/459/ I can reproduce with |
|
@H4ad the stress test passed. Would you mind sharing more information about your local test? Thank you. |
|
@legendecas Try with this code: 'use strict';
const assert = require('assert');
const common = require('../common.js');
const { createHistogram } = require('perf_hooks');
const bench = common.createBenchmark(main, {
n: [1e5],
operation: ['creation', 'clone'],
});
let _histogram;
function main({ n, operation }) {
switch (operation) {
case 'creation': {
bench.start();
for (let i = 0; i < n; i++)
_histogram = createHistogram();
bench.end(n);
// Avoid V8 deadcode (elimination)
assert.ok(_histogram);
break;
}
case 'clone': {
bench.start();
for (let i = 0; i < n; i++)
_histogram = structuredClone(createHistogram());
bench.end(n);
// Avoid V8 deadcode (elimination)
assert.ok(_histogram);
break;
}
default:
throw new Error(`Unsupported operation ${operation}`);
}
}Put it inside |
|
Note that |
|
Oh, you are right, I forgot to compile the old version with your patch, sorry about that. In this case, I can confirm this PR fixes my bug! Thanks for your work! |
|
Landed in 78a1570 |
JSTransferable wrapper object is a short-lived wrapper in the scope of the serialization or the deserialization. Make the JSTransferable wrapper object pointer as a strongly-referenced detached BaseObjectPtr so that a JSTransferable wrapper object and its target object will never be garbage-collected during a ser-des process, and the wrapper object will be immediately destroyed when the process is completed. PR-URL: nodejs#50026 Fixes: nodejs#49852 Fixes: nodejs#49844 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
JSTransferable wrapper object is a short-lived wrapper in the scope of the serialization or the deserialization. Make the JSTransferable wrapper object pointer as a strongly-referenced detached BaseObjectPtr so that a JSTransferable wrapper object and its target object will never be garbage-collected during a ser-des process, and the wrapper object will be immediately destroyed when the process is completed. PR-URL: nodejs#50026 Fixes: nodejs#49852 Fixes: nodejs#49844 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
JSTransferable wrapper object is a short-lived wrapper in the scope of
the serialization or the deserialization. Make the JSTransferable
wrapper object pointer as a strongly-referenced detached BaseObjectPtr
so that a JSTransferable wrapper object and its target object will never
be garbage-collected during a ser-des process, and the wrapper object
will be immediately destroyed when the process is completed.
Fixes: #49852
Fixes: #49844