GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — src: clear all linked module caches once instantiated · nodejs/node@84701ff

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • src
    • module_wrap.cc
    • module_wrap.h
  • test/parallel
    • test-internal-module-wrap.js
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/module_wrap.cc‎

Copy file name to clipboardExpand all lines: src/module_wrap.cc
+79-38Lines changed: 79 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,23 @@ ModuleWrap::ModuleWrap(Realm* realm,
123123
object->SetInternalField(kSyntheticEvaluationStepsSlot,
124124
synthetic_evaluation_step);
125125
object->SetInternalField(kContextObjectSlot, context_object);
126+
object->SetInternalField(kLinkedRequestsSlot,
127+
v8::Undefined(realm->isolate()));
126128

127129
if (!synthetic_evaluation_step->IsUndefined()) {
128130
synthetic_ = true;
129131
}
130132
MakeWeak();
131133
module_.SetWeak();
134+
135+
HandleScope scope(realm->isolate());
136+
Local<Context> context = realm->context();
137+
Local<FixedArray> requests = module->GetModuleRequests();
138+
for (int i = 0; i < requests->Length(); i++) {
139+
ModuleCacheKey module_cache_key = ModuleCacheKey::From(
140+
context, requests->Get(context, i).As<ModuleRequest>());
141+
resolve_cache_[module_cache_key] = i;
142+
}
132143
}
133144

134145
ModuleWrap::~ModuleWrap() {
@@ -149,6 +160,30 @@ Local<Context> ModuleWrap::context() const {
149160
return obj.As<Object>()->GetCreationContextChecked();
150161
}
151162

163+
ModuleWrap* ModuleWrap::GetLinkedRequest(uint32_t index) {
164+
DCHECK(IsLinked());
165+
Isolate* isolate = env()->isolate();
166+
EscapableHandleScope scope(isolate);
167+
Local<Data> linked_requests_data =
168+
object()->GetInternalField(kLinkedRequestsSlot);
169+
DCHECK(linked_requests_data->IsValue() &&
170+
linked_requests_data.As<Value>()->IsArray());
171+
Local<Array> requests = linked_requests_data.As<Array>();
172+
173+
CHECK_LT(index, requests->Length());
174+
175+
Local<Value> module_value;
176+
if (!requests->Get(context(), index).ToLocal(&module_value)) {
177+
return nullptr;
178+
}
179+
CHECK(module_value->IsObject());
180+
Local<Object> module_object = module_value.As<Object>();
181+
182+
ModuleWrap* module_wrap;
183+
ASSIGN_OR_RETURN_UNWRAP(&module_wrap, module_object, nullptr);
184+
return module_wrap;
185+
}
186+
152187
ModuleWrap* ModuleWrap::GetFromModule(Environment* env,
153188
Local<Module> module) {
154189
auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash());
@@ -542,34 +577,28 @@ void ModuleWrap::GetModuleRequests(const FunctionCallbackInfo<Value>& args) {
542577
void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
543578
Realm* realm = Realm::GetCurrent(args);
544579
Isolate* isolate = args.GetIsolate();
545-
Local<Context> context = realm->context();
546580

547581
ModuleWrap* dependent;
548582
ASSIGN_OR_RETURN_UNWRAP(&dependent, args.This());
549583

550584
CHECK_EQ(args.Length(), 1);
551585

586+
Local<Data> linked_requests =
587+
args.This()->GetInternalField(kLinkedRequestsSlot);
588+
if (linked_requests->IsValue() &&
589+
!linked_requests.As<Value>()->IsUndefined()) {
590+
// If the module is already linked, we should not link it again.
591+
THROW_ERR_VM_MODULE_LINK_FAILURE(realm->env(), "module is already linked");
592+
return;
593+
}
594+
552595
Local<FixedArray> requests =
553596
dependent->module_.Get(isolate)->GetModuleRequests();
554597
Local<Array> modules = args[0].As<Array>();
555598
CHECK_EQ(modules->Length(), static_cast<uint32_t>(requests->Length()));
556599

557-
std::vector<Global<Value>> modules_buffer;
558-
if (FromV8Array(context, modules, &modules_buffer).IsNothing()) {
559-
return;
560-
}
561-
562-
for (uint32_t i = 0; i < modules_buffer.size(); i++) {
563-
Local<Object> module_object = modules_buffer[i].Get(isolate).As<Object>();
564-
565-
CHECK(
566-
realm->isolate_data()->module_wrap_constructor_template()->HasInstance(
567-
module_object));
568-
569-
ModuleCacheKey module_cache_key = ModuleCacheKey::From(
570-
context, requests->Get(context, i).As<ModuleRequest>());
571-
dependent->resolve_cache_[module_cache_key].Reset(isolate, module_object);
572-
}
600+
args.This()->SetInternalField(kLinkedRequestsSlot, modules);
601+
dependent->linked_ = true;
573602
}
574603

575604
void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
@@ -582,9 +611,6 @@ void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
582611
TryCatchScope try_catch(realm->env());
583612
USE(module->InstantiateModule(context, ResolveModuleCallback));
584613

585-
// clear resolve cache on instantiate
586-
obj->resolve_cache_.clear();
587-
588614
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
589615
CHECK(!try_catch.Message().IsEmpty());
590616
CHECK(!try_catch.Exception().IsEmpty());
@@ -731,9 +757,6 @@ void ModuleWrap::InstantiateSync(const FunctionCallbackInfo<Value>& args) {
731757
TryCatchScope try_catch(env);
732758
USE(module->InstantiateModule(context, ResolveModuleCallback));
733759

734-
// clear resolve cache on instantiate
735-
obj->resolve_cache_.clear();
736-
737760
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
738761
CHECK(!try_catch.Message().IsEmpty());
739762
CHECK(!try_catch.Exception().IsEmpty());
@@ -940,45 +963,63 @@ void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
940963
args.GetReturnValue().Set(module->GetException());
941964
}
942965

966+
// static
943967
MaybeLocal<Module> ModuleWrap::ResolveModuleCallback(
944968
Local<Context> context,
945969
Local<String> specifier,
946970
Local<FixedArray> import_attributes,
947971
Local<Module> referrer) {
972+
ModuleWrap* resolved_module;
973+
if (!ResolveModule(context, specifier, import_attributes, referrer)
974+
.To(&resolved_module)) {
975+
return {};
976+
}
977+
DCHECK_NOT_NULL(resolved_module);
978+
return resolved_module->module_.Get(context->GetIsolate());
979+
}
980+
981+
// static
982+
Maybe<ModuleWrap*> ModuleWrap::ResolveModule(
983+
Local<Context> context,
984+
Local<String> specifier,
985+
Local<FixedArray> import_attributes,
986+
Local<Module> referrer) {
948987
Isolate* isolate = context->GetIsolate();
949988
Environment* env = Environment::GetCurrent(context);
950989
if (env == nullptr) {
951990
THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate);
952-
return MaybeLocal<Module>();
991+
return Nothing<ModuleWrap*>();
953992
}
993+
// Check that the referrer is not yet been instantiated.
994+
DCHECK(referrer->GetStatus() <= Module::kInstantiated);
954995

955996
ModuleCacheKey cache_key =
956997
ModuleCacheKey::From(context, specifier, import_attributes);
957998

958-
ModuleWrap* dependent = GetFromModule(env, referrer);
999+
ModuleWrap* dependent = ModuleWrap::GetFromModule(env, referrer);
9591000
if (dependent == nullptr) {
9601001
THROW_ERR_VM_MODULE_LINK_FAILURE(
9611002
env, "request for '%s' is from invalid module", cache_key.specifier);
962-
return MaybeLocal<Module>();
1003+
return Nothing<ModuleWrap*>();
9631004
}
964-
965-
if (dependent->resolve_cache_.count(cache_key) != 1) {
1005+
if (!dependent->IsLinked()) {
9661006
THROW_ERR_VM_MODULE_LINK_FAILURE(
967-
env, "request for '%s' is not in cache", cache_key.specifier);
968-
return MaybeLocal<Module>();
1007+
env,
1008+
"request for '%s' is from a module not been linked",
1009+
cache_key.specifier);
1010+
return Nothing<ModuleWrap*>();
9691011
}
9701012

971-
Local<Object> module_object =
972-
dependent->resolve_cache_[cache_key].Get(isolate);
973-
if (module_object.IsEmpty() || !module_object->IsObject()) {
1013+
auto it = dependent->resolve_cache_.find(cache_key);
1014+
if (it == dependent->resolve_cache_.end()) {
9741015
THROW_ERR_VM_MODULE_LINK_FAILURE(
975-
env, "request for '%s' did not return an object", cache_key.specifier);
976-
return MaybeLocal<Module>();
1016+
env, "request for '%s' is not in cache", cache_key.specifier);
1017+
return Nothing<ModuleWrap*>();
9771018
}
9781019

979-
ModuleWrap* module;
980-
ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Module>());
981-
return module->module_.Get(isolate);
1020+
ModuleWrap* module_wrap = dependent->GetLinkedRequest(it->second);
1021+
CHECK_NOT_NULL(module_wrap);
1022+
return Just(module_wrap);
9821023
}
9831024

9841025
static MaybeLocal<Promise> ImportModuleDynamically(
Collapse file

‎src/module_wrap.h‎

Copy file name to clipboardExpand all lines: src/module_wrap.h
+20-8Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,16 @@ struct ModuleCacheKey : public MemoryRetainer {
8484
};
8585

8686
class ModuleWrap : public BaseObject {
87+
using ResolveCache =
88+
std::unordered_map<ModuleCacheKey, uint32_t, ModuleCacheKey::Hash>;
89+
8790
public:
8891
enum InternalFields {
8992
kModuleSlot = BaseObject::kInternalFieldCount,
9093
kURLSlot,
9194
kSyntheticEvaluationStepsSlot,
92-
kContextObjectSlot, // Object whose creation context is the target Context
95+
kContextObjectSlot, // Object whose creation context is the target Context
96+
kLinkedRequestsSlot, // Array of linked requests
9397
kInternalFieldCount
9498
};
9599

@@ -105,23 +109,25 @@ class ModuleWrap : public BaseObject {
105109
v8::Local<v8::Module> module,
106110
v8::Local<v8::Object> meta);
107111

108-
void MemoryInfo(MemoryTracker* tracker) const override {
109-
tracker->TrackField("resolve_cache", resolve_cache_);
110-
}
111112
static void HasTopLevelAwait(const v8::FunctionCallbackInfo<v8::Value>& args);
112113

113114
v8::Local<v8::Context> context() const;
114115
v8::Maybe<bool> CheckUnsettledTopLevelAwait();
115116

116117
SET_MEMORY_INFO_NAME(ModuleWrap)
117118
SET_SELF_SIZE(ModuleWrap)
119+
SET_NO_MEMORY_INFO()
118120

119121
bool IsNotIndicativeOfMemoryLeakAtExit() const override {
120122
// XXX: The garbage collection rules for ModuleWrap are *super* unclear.
121123
// Do these objects ever get GC'd? Are we just okay with leaking them?
122124
return true;
123125
}
124126

127+
bool IsLinked() const { return linked_; }
128+
129+
ModuleWrap* GetLinkedRequest(uint32_t index);
130+
125131
static v8::Local<v8::PrimitiveArray> GetHostDefinedOptions(
126132
v8::Isolate* isolate, v8::Local<v8::Symbol> symbol);
127133

@@ -183,13 +189,19 @@ class ModuleWrap : public BaseObject {
183189
v8::Local<v8::Module> referrer);
184190
static ModuleWrap* GetFromModule(node::Environment*, v8::Local<v8::Module>);
185191

192+
// This method may throw a JavaScript exception, so the return type is
193+
// wrapped in a Maybe.
194+
static v8::Maybe<ModuleWrap*> ResolveModule(
195+
v8::Local<v8::Context> context,
196+
v8::Local<v8::String> specifier,
197+
v8::Local<v8::FixedArray> import_attributes,
198+
v8::Local<v8::Module> referrer);
199+
186200
v8::Global<v8::Module> module_;
187-
std::unordered_map<ModuleCacheKey,
188-
v8::Global<v8::Object>,
189-
ModuleCacheKey::Hash>
190-
resolve_cache_;
201+
ResolveCache resolve_cache_;
191202
contextify::ContextifyContext* contextify_context_ = nullptr;
192203
bool synthetic_ = false;
204+
bool linked_ = false;
193205
int module_hash_;
194206
};
195207

Collapse file

‎test/parallel/test-internal-module-wrap.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-internal-module-wrap.js
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,21 @@ const assert = require('assert');
66
const { internalBinding } = require('internal/test/binding');
77
const { ModuleWrap } = internalBinding('module_wrap');
88

9+
const unlinked = new ModuleWrap('unlinked', undefined, 'export * from "bar";', 0, 0);
10+
assert.throws(() => {
11+
unlinked.instantiate();
12+
}, {
13+
code: 'ERR_VM_MODULE_LINK_FAILURE',
14+
});
15+
16+
const dependsOnUnlinked = new ModuleWrap('dependsOnUnlinked', undefined, 'export * from "unlinked";', 0, 0);
17+
dependsOnUnlinked.link([unlinked]);
18+
assert.throws(() => {
19+
dependsOnUnlinked.instantiate();
20+
}, {
21+
code: 'ERR_VM_MODULE_LINK_FAILURE',
22+
});
23+
924
const foo = new ModuleWrap('foo', undefined, 'export * from "bar";', 0, 0);
1025
const bar = new ModuleWrap('bar', undefined, 'export const five = 5', 0, 0);
1126

@@ -22,4 +37,5 @@ const bar = new ModuleWrap('bar', undefined, 'export const five = 5', 0, 0);
2237

2338
// Check that the module requests are the same after linking, instantiate, and evaluation.
2439
assert.deepStrictEqual(moduleRequests, foo.getModuleRequests());
40+
2541
})().then(common.mustCall());

0 commit comments

Comments
0 (0)
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.