mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
vm: migrate ContextifyScript to cppgc
This patch migrates ContextifyScript to cppgc-based memory management using CppgcMixin. PR-URL: https://github.com/nodejs/node/pull/52295 Refs: https://github.com/nodejs/node/issues/40786 Refs: https://docs.google.com/document/d/1ny2Qz_EsUnXGKJRGxoA-FXIE2xpLgaMAN6jD7eAkqFQ/edit Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
This commit is contained in:
parent
849db10fb3
commit
3b0617dd19
@ -5,17 +5,17 @@
|
|||||||
const common = require('../common.js');
|
const common = require('../common.js');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const vm = require('vm');
|
const vm = require('vm');
|
||||||
const fixtures = require('../../test/common/fixtures.js');
|
const path = require('path');
|
||||||
const scriptPath = fixtures.path('snapshot', 'typescript.js');
|
|
||||||
|
|
||||||
const bench = common.createBenchmark(main, {
|
const bench = common.createBenchmark(main, {
|
||||||
type: ['with-dynamic-import-callback', 'without-dynamic-import-callback'],
|
type: ['with-dynamic-import-callback', 'without-dynamic-import-callback'],
|
||||||
n: [100],
|
filename: ['test/fixtures/snapshot/typescript.js', 'test/fixtures/syntax/good_syntax.js'],
|
||||||
|
n: [1000],
|
||||||
});
|
});
|
||||||
|
|
||||||
const scriptSource = fs.readFileSync(scriptPath, 'utf8');
|
function main({ n, type, filename }) {
|
||||||
|
const scriptPath = path.resolve(__dirname, '..', '..', filename);
|
||||||
function main({ n, type }) {
|
const scriptSource = fs.readFileSync(scriptPath, 'utf8');
|
||||||
let script;
|
let script;
|
||||||
bench.start();
|
bench.start();
|
||||||
const options = {};
|
const options = {};
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "node_contextify.h"
|
#include "node_contextify.h"
|
||||||
|
|
||||||
#include "base_object-inl.h"
|
#include "base_object-inl.h"
|
||||||
|
#include "cppgc/allocation.h"
|
||||||
#include "memory_tracker-inl.h"
|
#include "memory_tracker-inl.h"
|
||||||
#include "module_wrap.h"
|
#include "module_wrap.h"
|
||||||
#include "node_context_data.h"
|
#include "node_context_data.h"
|
||||||
@ -960,6 +961,12 @@ void ContextifyScript::RegisterExternalReferences(
|
|||||||
registry->Register(RunInContext);
|
registry->Register(RunInContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContextifyScript* ContextifyScript::New(Environment* env,
|
||||||
|
Local<Object> object) {
|
||||||
|
return cppgc::MakeGarbageCollected<ContextifyScript>(
|
||||||
|
env->isolate()->GetCppHeap()->GetAllocationHandle(), env, object);
|
||||||
|
}
|
||||||
|
|
||||||
void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
|
void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
Isolate* isolate = env->isolate();
|
Isolate* isolate = env->isolate();
|
||||||
@ -1010,8 +1017,7 @@ void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
id_symbol = args[7].As<Symbol>();
|
id_symbol = args[7].As<Symbol>();
|
||||||
}
|
}
|
||||||
|
|
||||||
ContextifyScript* contextify_script =
|
ContextifyScript* contextify_script = New(env, args.This());
|
||||||
new ContextifyScript(env, args.This());
|
|
||||||
|
|
||||||
if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
|
if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
|
||||||
TRACING_CATEGORY_NODE2(vm, script)) != 0) {
|
TRACING_CATEGORY_NODE2(vm, script)) != 0) {
|
||||||
@ -1069,9 +1075,7 @@ void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
contextify_script->script_.Reset(isolate, v8_script);
|
contextify_script->set_unbound_script(v8_script);
|
||||||
contextify_script->script_.SetWeak();
|
|
||||||
contextify_script->object()->SetInternalField(kUnboundScriptSlot, v8_script);
|
|
||||||
|
|
||||||
std::unique_ptr<ScriptCompiler::CachedData> new_cached_data;
|
std::unique_ptr<ScriptCompiler::CachedData> new_cached_data;
|
||||||
if (produce_cached_data) {
|
if (produce_cached_data) {
|
||||||
@ -1174,11 +1178,9 @@ void ContextifyScript::CreateCachedData(
|
|||||||
const FunctionCallbackInfo<Value>& args) {
|
const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
ContextifyScript* wrapped_script;
|
ContextifyScript* wrapped_script;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.This());
|
ASSIGN_OR_RETURN_UNWRAP_CPPGC(&wrapped_script, args.This());
|
||||||
Local<UnboundScript> unbound_script =
|
|
||||||
PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
|
|
||||||
std::unique_ptr<ScriptCompiler::CachedData> cached_data(
|
std::unique_ptr<ScriptCompiler::CachedData> cached_data(
|
||||||
ScriptCompiler::CreateCodeCache(unbound_script));
|
ScriptCompiler::CreateCodeCache(wrapped_script->unbound_script()));
|
||||||
if (!cached_data) {
|
if (!cached_data) {
|
||||||
args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
|
args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
|
||||||
} else {
|
} else {
|
||||||
@ -1192,9 +1194,8 @@ void ContextifyScript::CreateCachedData(
|
|||||||
|
|
||||||
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
|
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
|
||||||
ContextifyScript* wrapped_script;
|
ContextifyScript* wrapped_script;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.This());
|
ASSIGN_OR_RETURN_UNWRAP_CPPGC(&wrapped_script, args.This());
|
||||||
|
|
||||||
CHECK_EQ(args.Length(), 5);
|
CHECK_EQ(args.Length(), 5);
|
||||||
CHECK(args[0]->IsObject() || args[0]->IsNull());
|
CHECK(args[0]->IsObject() || args[0]->IsNull());
|
||||||
@ -1264,10 +1265,9 @@ bool ContextifyScript::EvalMachine(Local<Context> context,
|
|||||||
|
|
||||||
TryCatchScope try_catch(env);
|
TryCatchScope try_catch(env);
|
||||||
ContextifyScript* wrapped_script;
|
ContextifyScript* wrapped_script;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.This(), false);
|
ASSIGN_OR_RETURN_UNWRAP_CPPGC(&wrapped_script, args.This(), false);
|
||||||
Local<UnboundScript> unbound_script =
|
Local<Script> script =
|
||||||
PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
|
wrapped_script->unbound_script()->BindToCurrentContext();
|
||||||
Local<Script> script = unbound_script->BindToCurrentContext();
|
|
||||||
|
|
||||||
#if HAVE_INSPECTOR
|
#if HAVE_INSPECTOR
|
||||||
if (break_on_first_line) {
|
if (break_on_first_line) {
|
||||||
@ -1349,9 +1349,21 @@ bool ContextifyScript::EvalMachine(Local<Context> context,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContextifyScript::ContextifyScript(Environment* env, Local<Object> object)
|
Local<UnboundScript> ContextifyScript::unbound_script() const {
|
||||||
: BaseObject(env, object) {
|
return script_.Get(env()->isolate());
|
||||||
MakeWeak();
|
}
|
||||||
|
|
||||||
|
void ContextifyScript::set_unbound_script(Local<UnboundScript> script) {
|
||||||
|
script_.Reset(env()->isolate(), script);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextifyScript::Trace(cppgc::Visitor* visitor) const {
|
||||||
|
CppgcMixin::Trace(visitor);
|
||||||
|
visitor->Trace(script_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextifyScript::ContextifyScript(Environment* env, Local<Object> object) {
|
||||||
|
CppgcMixin::Wrap(this, env, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
ContextifyScript::~ContextifyScript() {}
|
ContextifyScript::~ContextifyScript() {}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||||
|
|
||||||
#include "base_object-inl.h"
|
#include "base_object-inl.h"
|
||||||
|
#include "cppgc_helpers.h"
|
||||||
#include "node_context_data.h"
|
#include "node_context_data.h"
|
||||||
#include "node_errors.h"
|
#include "node_errors.h"
|
||||||
|
|
||||||
@ -143,23 +144,21 @@ class ContextifyContext : public BaseObject {
|
|||||||
std::unique_ptr<v8::MicrotaskQueue> microtask_queue_;
|
std::unique_ptr<v8::MicrotaskQueue> microtask_queue_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContextifyScript : public BaseObject {
|
class ContextifyScript final : CPPGC_MIXIN(ContextifyScript) {
|
||||||
public:
|
public:
|
||||||
enum InternalFields {
|
SET_CPPGC_NAME(ContextifyScript)
|
||||||
kUnboundScriptSlot = BaseObject::kInternalFieldCount,
|
void Trace(cppgc::Visitor* visitor) const final;
|
||||||
kInternalFieldCount
|
|
||||||
};
|
|
||||||
|
|
||||||
SET_NO_MEMORY_INFO()
|
|
||||||
SET_MEMORY_INFO_NAME(ContextifyScript)
|
|
||||||
SET_SELF_SIZE(ContextifyScript)
|
|
||||||
|
|
||||||
ContextifyScript(Environment* env, v8::Local<v8::Object> object);
|
ContextifyScript(Environment* env, v8::Local<v8::Object> object);
|
||||||
~ContextifyScript() override;
|
~ContextifyScript() override;
|
||||||
|
|
||||||
|
v8::Local<v8::UnboundScript> unbound_script() const;
|
||||||
|
void set_unbound_script(v8::Local<v8::UnboundScript>);
|
||||||
|
|
||||||
static void CreatePerIsolateProperties(IsolateData* isolate_data,
|
static void CreatePerIsolateProperties(IsolateData* isolate_data,
|
||||||
v8::Local<v8::ObjectTemplate> target);
|
v8::Local<v8::ObjectTemplate> target);
|
||||||
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
|
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
|
||||||
|
static ContextifyScript* New(Environment* env, v8::Local<v8::Object> object);
|
||||||
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static bool InstanceOf(Environment* env, const v8::Local<v8::Value>& args);
|
static bool InstanceOf(Environment* env, const v8::Local<v8::Value>& args);
|
||||||
static void CreateCachedData(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void CreateCachedData(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
@ -174,7 +173,7 @@ class ContextifyScript : public BaseObject {
|
|||||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
v8::Global<v8::UnboundScript> script_;
|
v8::TracedReference<v8::UnboundScript> script_;
|
||||||
};
|
};
|
||||||
|
|
||||||
v8::Maybe<bool> StoreCodeCacheResult(
|
v8::Maybe<bool> StoreCodeCacheResult(
|
||||||
|
@ -2,17 +2,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// This tests that Environment is tracked in heap snapshots.
|
// This tests that Environment is tracked in heap snapshots.
|
||||||
|
// Tests for BaseObject and cppgc-managed objects are done in other
|
||||||
|
// test-heapdump-*.js files.
|
||||||
|
|
||||||
require('../common');
|
require('../common');
|
||||||
const { validateSnapshotNodes } = require('../common/heap');
|
const { validateSnapshotNodes } = require('../common/heap');
|
||||||
|
|
||||||
// This is just using ContextifyScript as an example here, it can be replaced
|
|
||||||
// with any BaseObject that we can easily instantiate here and register in
|
|
||||||
// cleanup hooks.
|
|
||||||
// These can all be changed to reflect the status of how these objects
|
|
||||||
// are captured in the snapshot.
|
|
||||||
const context = require('vm').createScript('const foo = 123');
|
|
||||||
|
|
||||||
validateSnapshotNodes('Node / Environment', [{
|
validateSnapshotNodes('Node / Environment', [{
|
||||||
children: [
|
children: [
|
||||||
{ node_name: 'Node / CleanupQueue', edge_name: 'cleanup_queue' },
|
{ node_name: 'Node / CleanupQueue', edge_name: 'cleanup_queue' },
|
||||||
@ -21,21 +16,8 @@ validateSnapshotNodes('Node / Environment', [{
|
|||||||
],
|
],
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
validateSnapshotNodes('Node / CleanupQueue', [
|
|
||||||
// The first one is the cleanup_queue of the Environment.
|
|
||||||
{},
|
|
||||||
// The second one is the cleanup_queue of the principal realm.
|
|
||||||
{
|
|
||||||
children: [
|
|
||||||
{ node_name: 'Node / ContextifyScript' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
validateSnapshotNodes('Node / PrincipalRealm', [{
|
validateSnapshotNodes('Node / PrincipalRealm', [{
|
||||||
children: [
|
children: [
|
||||||
{ node_name: 'process', edge_name: 'process_object' },
|
{ node_name: 'process', edge_name: 'process_object' },
|
||||||
],
|
],
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
console.log(context); // Make sure it's not GC'ed
|
|
||||||
|
13
test/pummel/test-heapdump-vm-script.js
Normal file
13
test/pummel/test-heapdump-vm-script.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
require('../common');
|
||||||
|
const { findByRetainingPath } = require('../common/heap');
|
||||||
|
const source = 'const foo = 123';
|
||||||
|
const script = require('vm').createScript(source);
|
||||||
|
|
||||||
|
findByRetainingPath('Node / ContextifyScript', [
|
||||||
|
{ node_name: '(shared function info)' }, // This is the UnboundScript referenced by ContextifyScript.
|
||||||
|
{ edge_name: 'script' },
|
||||||
|
{ edge_name: 'source', node_type: 'string', node_name: source },
|
||||||
|
]);
|
||||||
|
|
||||||
|
console.log(script); // Keep the script alive.
|
Loading…
Reference in New Issue
Block a user