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@6a47ff4

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
+96-78Lines changed: 96 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,23 @@ ModuleWrap::ModuleWrap(Realm* realm,
133133
object->SetInternalField(kSyntheticEvaluationStepsSlot,
134134
synthetic_evaluation_step);
135135
object->SetInternalField(kContextObjectSlot, context_object);
136+
object->SetInternalField(kLinkedRequestsSlot,
137+
v8::Undefined(realm->isolate()));
136138

137139
if (!synthetic_evaluation_step->IsUndefined()) {
138140
synthetic_ = true;
139141
}
140142
MakeWeak();
141143
module_.SetWeak();
144+
145+
HandleScope scope(realm->isolate());
146+
Local<Context> context = realm->context();
147+
Local<FixedArray> requests = module->GetModuleRequests();
148+
for (int i = 0; i < requests->Length(); i++) {
149+
ModuleCacheKey module_cache_key = ModuleCacheKey::From(
150+
context, requests->Get(context, i).As<ModuleRequest>());
151+
resolve_cache_[module_cache_key] = i;
152+
}
142153
}
143154

144155
ModuleWrap::~ModuleWrap() {
@@ -159,6 +170,30 @@ Local<Context> ModuleWrap::context() const {
159170
return obj.As<Object>()->GetCreationContextChecked();
160171
}
161172

173+
ModuleWrap* ModuleWrap::GetLinkedRequest(uint32_t index) {
174+
DCHECK(IsLinked());
175+
Isolate* isolate = env()->isolate();
176+
EscapableHandleScope scope(isolate);
177+
Local<Data> linked_requests_data =
178+
object()->GetInternalField(kLinkedRequestsSlot);
179+
DCHECK(linked_requests_data->IsValue() &&
180+
linked_requests_data.As<Value>()->IsArray());
181+
Local<Array> requests = linked_requests_data.As<Array>();
182+
183+
CHECK_LT(index, requests->Length());
184+
185+
Local<Value> module_value;
186+
if (!requests->Get(context(), index).ToLocal(&module_value)) {
187+
return nullptr;
188+
}
189+
CHECK(module_value->IsObject());
190+
Local<Object> module_object = module_value.As<Object>();
191+
192+
ModuleWrap* module_wrap;
193+
ASSIGN_OR_RETURN_UNWRAP(&module_wrap, module_object, nullptr);
194+
return module_wrap;
195+
}
196+
162197
ModuleWrap* ModuleWrap::GetFromModule(Environment* env,
163198
Local<Module> module) {
164199
auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash());
@@ -571,34 +606,28 @@ void ModuleWrap::GetModuleRequests(const FunctionCallbackInfo<Value>& args) {
571606
void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
572607
Realm* realm = Realm::GetCurrent(args);
573608
Isolate* isolate = args.GetIsolate();
574-
Local<Context> context = realm->context();
575609

576610
ModuleWrap* dependent;
577611
ASSIGN_OR_RETURN_UNWRAP(&dependent, args.This());
578612

579613
CHECK_EQ(args.Length(), 1);
580614

615+
Local<Data> linked_requests =
616+
args.This()->GetInternalField(kLinkedRequestsSlot);
617+
if (linked_requests->IsValue() &&
618+
!linked_requests.As<Value>()->IsUndefined()) {
619+
// If the module is already linked, we should not link it again.
620+
THROW_ERR_VM_MODULE_LINK_FAILURE(realm->env(), "module is already linked");
621+
return;
622+
}
623+
581624
Local<FixedArray> requests =
582625
dependent->module_.Get(isolate)->GetModuleRequests();
583626
Local<Array> modules = args[0].As<Array>();
584627
CHECK_EQ(modules->Length(), static_cast<uint32_t>(requests->Length()));
585628

586-
std::vector<Global<Value>> modules_buffer;
587-
if (FromV8Array(context, modules, &modules_buffer).IsNothing()) {
588-
return;
589-
}
590-
591-
for (uint32_t i = 0; i < modules_buffer.size(); i++) {
592-
Local<Object> module_object = modules_buffer[i].Get(isolate).As<Object>();
593-
594-
CHECK(
595-
realm->isolate_data()->module_wrap_constructor_template()->HasInstance(
596-
module_object));
597-
598-
ModuleCacheKey module_cache_key = ModuleCacheKey::From(
599-
context, requests->Get(context, i).As<ModuleRequest>());
600-
dependent->resolve_cache_[module_cache_key].Reset(isolate, module_object);
601-
}
629+
args.This()->SetInternalField(kLinkedRequestsSlot, modules);
630+
dependent->linked_ = true;
602631
}
603632

604633
void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
@@ -612,9 +641,6 @@ void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
612641
USE(module->InstantiateModule(
613642
context, ResolveModuleCallback, ResolveSourceCallback));
614643

615-
// clear resolve cache on instantiate
616-
obj->resolve_cache_.clear();
617-
618644
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
619645
CHECK(!try_catch.Message().IsEmpty());
620646
CHECK(!try_catch.Exception().IsEmpty());
@@ -722,9 +748,6 @@ void ModuleWrap::InstantiateSync(const FunctionCallbackInfo<Value>& args) {
722748
USE(module->InstantiateModule(
723749
context, ResolveModuleCallback, ResolveSourceCallback));
724750

725-
// clear resolve cache on instantiate
726-
obj->resolve_cache_.clear();
727-
728751
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
729752
CHECK(!try_catch.Message().IsEmpty());
730753
CHECK(!try_catch.Exception().IsEmpty());
@@ -965,48 +988,51 @@ void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
965988
args.GetReturnValue().Set(module->GetException());
966989
}
967990

991+
// static
968992
MaybeLocal<Module> ModuleWrap::ResolveModuleCallback(
969993
Local<Context> context,
970994
Local<String> specifier,
971995
Local<FixedArray> import_attributes,
972996
Local<Module> referrer) {
973-
Isolate* isolate = context->GetIsolate();
974-
Environment* env = Environment::GetCurrent(context);
975-
if (env == nullptr) {
976-
THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate);
977-
return MaybeLocal<Module>();
978-
}
979-
980-
ModuleCacheKey cache_key =
981-
ModuleCacheKey::From(context, specifier, import_attributes);
982-
983-
ModuleWrap* dependent = GetFromModule(env, referrer);
984-
if (dependent == nullptr) {
985-
THROW_ERR_VM_MODULE_LINK_FAILURE(
986-
env, "request for '%s' is from invalid module", cache_key.specifier);
987-
return MaybeLocal<Module>();
997+
ModuleWrap* resolved_module;
998+
if (!ResolveModule(context, specifier, import_attributes, referrer)
999+
.To(&resolved_module)) {
1000+
return {};
9881001
}
1002+
DCHECK_NOT_NULL(resolved_module);
1003+
return resolved_module->module_.Get(context->GetIsolate());
1004+
}
9891005

990-
if (dependent->resolve_cache_.count(cache_key) != 1) {
991-
THROW_ERR_VM_MODULE_LINK_FAILURE(
992-
env, "request for '%s' is not in cache", cache_key.specifier);
993-
return MaybeLocal<Module>();
1006+
// static
1007+
MaybeLocal<Object> ModuleWrap::ResolveSourceCallback(
1008+
Local<Context> context,
1009+
Local<String> specifier,
1010+
Local<FixedArray> import_attributes,
1011+
Local<Module> referrer) {
1012+
ModuleWrap* resolved_module;
1013+
if (!ResolveModule(context, specifier, import_attributes, referrer)
1014+
.To(&resolved_module)) {
1015+
return {};
9941016
}
1017+
DCHECK_NOT_NULL(resolved_module);
9951018

996-
Local<Object> module_object =
997-
dependent->resolve_cache_[cache_key].Get(isolate);
998-
if (module_object.IsEmpty() || !module_object->IsObject()) {
999-
THROW_ERR_VM_MODULE_LINK_FAILURE(
1000-
env, "request for '%s' did not return an object", cache_key.specifier);
1001-
return MaybeLocal<Module>();
1019+
Local<Value> module_source_object =
1020+
resolved_module->object()
1021+
->GetInternalField(ModuleWrap::kModuleSourceObjectSlot)
1022+
.As<Value>();
1023+
if (module_source_object->IsUndefined()) {
1024+
Local<String> url = resolved_module->object()
1025+
->GetInternalField(ModuleWrap::kURLSlot)
1026+
.As<String>();
1027+
THROW_ERR_SOURCE_PHASE_NOT_DEFINED(context->GetIsolate(), url);
1028+
return {};
10021029
}
1003-
1004-
ModuleWrap* module;
1005-
ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Module>());
1006-
return module->module_.Get(isolate);
1030+
CHECK(module_source_object->IsObject());
1031+
return module_source_object.As<Object>();
10071032
}
10081033

1009-
MaybeLocal<Object> ModuleWrap::ResolveSourceCallback(
1034+
// static
1035+
Maybe<ModuleWrap*> ModuleWrap::ResolveModule(
10101036
Local<Context> context,
10111037
Local<String> specifier,
10121038
Local<FixedArray> import_attributes,
@@ -1015,46 +1041,38 @@ MaybeLocal<Object> ModuleWrap::ResolveSourceCallback(
10151041
Environment* env = Environment::GetCurrent(context);
10161042
if (env == nullptr) {
10171043
THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate);
1018-
return MaybeLocal<Object>();
1044+
return Nothing<ModuleWrap*>();
10191045
}
1046+
// Check that the referrer is not yet been instantiated.
1047+
DCHECK(referrer->GetStatus() <= Module::kInstantiated);
10201048

10211049
ModuleCacheKey cache_key =
10221050
ModuleCacheKey::From(context, specifier, import_attributes);
10231051

1024-
ModuleWrap* dependent = GetFromModule(env, referrer);
1052+
ModuleWrap* dependent = ModuleWrap::GetFromModule(env, referrer);
10251053
if (dependent == nullptr) {
10261054
THROW_ERR_VM_MODULE_LINK_FAILURE(
10271055
env, "request for '%s' is from invalid module", cache_key.specifier);
1028-
return MaybeLocal<Object>();
1056+
return Nothing<ModuleWrap*>();
10291057
}
1030-
1031-
if (dependent->resolve_cache_.count(cache_key) != 1) {
1058+
if (!dependent->IsLinked()) {
10321059
THROW_ERR_VM_MODULE_LINK_FAILURE(
1033-
env, "request for '%s' is not in cache", cache_key.specifier);
1034-
return MaybeLocal<Object>();
1060+
env,
1061+
"request for '%s' is from a module not been linked",
1062+
cache_key.specifier);
1063+
return Nothing<ModuleWrap*>();
10351064
}
10361065

1037-
Local<Object> module_object =
1038-
dependent->resolve_cache_[cache_key].Get(isolate);
1039-
if (module_object.IsEmpty() || !module_object->IsObject()) {
1066+
auto it = dependent->resolve_cache_.find(cache_key);
1067+
if (it == dependent->resolve_cache_.end()) {
10401068
THROW_ERR_VM_MODULE_LINK_FAILURE(
1041-
env, "request for '%s' did not return an object", cache_key.specifier);
1042-
return MaybeLocal<Object>();
1069+
env, "request for '%s' is not in cache", cache_key.specifier);
1070+
return Nothing<ModuleWrap*>();
10431071
}
10441072

1045-
ModuleWrap* module;
1046-
ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Object>());
1047-
1048-
Local<Value> module_source_object =
1049-
module->object()->GetInternalField(kModuleSourceObjectSlot).As<Value>();
1050-
if (module_source_object->IsUndefined()) {
1051-
Local<String> url =
1052-
module->object()->GetInternalField(kURLSlot).As<String>();
1053-
THROW_ERR_SOURCE_PHASE_NOT_DEFINED(isolate, url);
1054-
return MaybeLocal<Object>();
1055-
}
1056-
CHECK(module_source_object->IsObject());
1057-
return module_source_object.As<Object>();
1073+
ModuleWrap* module_wrap = dependent->GetLinkedRequest(it->second);
1074+
CHECK_NOT_NULL(module_wrap);
1075+
return Just(module_wrap);
10581076
}
10591077

10601078
static MaybeLocal<Promise> ImportModuleDynamicallyWithPhase(
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
@@ -90,13 +90,17 @@ struct ModuleCacheKey : public MemoryRetainer {
9090
};
9191

9292
class ModuleWrap : public BaseObject {
93+
using ResolveCache =
94+
std::unordered_map<ModuleCacheKey, uint32_t, ModuleCacheKey::Hash>;
95+
9396
public:
9497
enum InternalFields {
9598
kModuleSlot = BaseObject::kInternalFieldCount,
9699
kURLSlot,
97100
kModuleSourceObjectSlot,
98101
kSyntheticEvaluationStepsSlot,
99-
kContextObjectSlot, // Object whose creation context is the target Context
102+
kContextObjectSlot, // Object whose creation context is the target Context
103+
kLinkedRequestsSlot, // Array of linked requests
100104
kInternalFieldCount
101105
};
102106

@@ -112,23 +116,25 @@ class ModuleWrap : public BaseObject {
112116
v8::Local<v8::Module> module,
113117
v8::Local<v8::Object> meta);
114118

115-
void MemoryInfo(MemoryTracker* tracker) const override {
116-
tracker->TrackField("resolve_cache", resolve_cache_);
117-
}
118119
static void HasTopLevelAwait(const v8::FunctionCallbackInfo<v8::Value>& args);
119120

120121
v8::Local<v8::Context> context() const;
121122
v8::Maybe<bool> CheckUnsettledTopLevelAwait();
122123

123124
SET_MEMORY_INFO_NAME(ModuleWrap)
124125
SET_SELF_SIZE(ModuleWrap)
126+
SET_NO_MEMORY_INFO()
125127

126128
bool IsNotIndicativeOfMemoryLeakAtExit() const override {
127129
// XXX: The garbage collection rules for ModuleWrap are *super* unclear.
128130
// Do these objects ever get GC'd? Are we just okay with leaking them?
129131
return true;
130132
}
131133

134+
bool IsLinked() const { return linked_; }
135+
136+
ModuleWrap* GetLinkedRequest(uint32_t index);
137+
132138
static v8::Local<v8::PrimitiveArray> GetHostDefinedOptions(
133139
v8::Isolate* isolate, v8::Local<v8::Symbol> symbol);
134140

@@ -199,13 +205,19 @@ class ModuleWrap : public BaseObject {
199205
v8::Local<v8::Module> referrer);
200206
static ModuleWrap* GetFromModule(node::Environment*, v8::Local<v8::Module>);
201207

208+
// This method may throw a JavaScript exception, so the return type is
209+
// wrapped in a Maybe.
210+
static v8::Maybe<ModuleWrap*> ResolveModule(
211+
v8::Local<v8::Context> context,
212+
v8::Local<v8::String> specifier,
213+
v8::Local<v8::FixedArray> import_attributes,
214+
v8::Local<v8::Module> referrer);
215+
202216
v8::Global<v8::Module> module_;
203-
std::unordered_map<ModuleCacheKey,
204-
v8::Global<v8::Object>,
205-
ModuleCacheKey::Hash>
206-
resolve_cache_;
217+
ResolveCache resolve_cache_;
207218
contextify::ContextifyContext* contextify_context_ = nullptr;
208219
bool synthetic_ = false;
220+
bool linked_ = false;
209221
int module_hash_;
210222
};
211223

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.