diff --git a/src/env_properties.h b/src/env_properties.h index 623e3022856989..7553823a9be48a 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -20,6 +20,7 @@ #define PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V) \ V(arrow_message_private_symbol, "node:arrowMessage") \ V(contextify_context_private_symbol, "node:contextify:context") \ + V(compiled_function_entry, "node:compiled_function_entry") \ V(decorated_private_symbol, "node:decorated") \ V(napi_type_tag, "node:napi:type_tag") \ V(napi_wrapper, "node:napi:wrapper") \ diff --git a/src/node_contextify.cc b/src/node_contextify.cc index d618dafcb5f14d..2a4d4618dbd2a3 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -77,7 +77,6 @@ using v8::Uint32; using v8::UnboundScript; using v8::Value; using v8::WeakCallbackInfo; -using v8::WeakCallbackType; // The vm module executes code in a sandboxed environment with a different // global object than the rest of the code. This is achieved by applying @@ -1263,8 +1262,7 @@ void ContextifyContext::CompileFunction( context).ToLocal(&cache_key)) { return; } - CompiledFnEntry* entry = new CompiledFnEntry(env, cache_key, id, fn); - env->id_to_function_map.emplace(id, entry); + new CompiledFnEntry(env, cache_key, id, fn); Local result = Object::New(isolate); if (result->Set(parsing_context, env->function_string(), fn).IsNothing()) @@ -1296,23 +1294,18 @@ void ContextifyContext::CompileFunction( args.GetReturnValue().Set(result); } -void CompiledFnEntry::WeakCallback( - const WeakCallbackInfo& data) { - CompiledFnEntry* entry = data.GetParameter(); - delete entry; -} - CompiledFnEntry::CompiledFnEntry(Environment* env, Local object, uint32_t id, Local fn) - : BaseObject(env, object), id_(id), fn_(env->isolate(), fn) { - fn_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter); + : BaseObject(env, object), id_(id) { + MakeWeak(); + fn->SetPrivate(env->context(), env->compiled_function_entry(), object); + env->id_to_function_map.emplace(id, this); } CompiledFnEntry::~CompiledFnEntry() { env()->id_to_function_map.erase(id_); - fn_.ClearWeak(); } static void StartSigintWatchdog(const FunctionCallbackInfo& args) { diff --git a/src/node_contextify.h b/src/node_contextify.h index 76c89318bb6cbf..a9b7741e61b2c2 100644 --- a/src/node_contextify.h +++ b/src/node_contextify.h @@ -194,9 +194,6 @@ class CompiledFnEntry final : public BaseObject { private: uint32_t id_; - v8::Global fn_; - - static void WeakCallback(const v8::WeakCallbackInfo& data); }; v8::Maybe StoreCodeCacheResult( diff --git a/test/pummel/test-vm-compile-function-leak.js b/test/pummel/test-vm-compile-function-leak.js new file mode 100644 index 00000000000000..465f300d4310d1 --- /dev/null +++ b/test/pummel/test-vm-compile-function-leak.js @@ -0,0 +1,14 @@ +'use strict'; + +// Flags: --max-old-space-size=10 + +require('../common'); +const vm = require('vm'); + +const code = `console.log("${'hello world '.repeat(1e5)}");`; + +for (let i = 0; i < 10000; i++) { + vm.compileFunction(code, [], { + importModuleDynamically: () => {}, + }); +}