Skip to content

Commit ba0be9b

Browse files
committed
src: add node_modules.h for module loader
1 parent cd6b86b commit ba0be9b

File tree

14 files changed

+241
-76
lines changed

14 files changed

+241
-76
lines changed

lib/internal/modules/package_json_reader.js

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
const {
44
JSONParse,
55
ObjectPrototypeHasOwnProperty,
6-
SafeMap,
76
StringPrototypeEndsWith,
87
StringPrototypeIndexOf,
98
StringPrototypeLastIndexOf,
@@ -12,15 +11,13 @@ const {
1211
const {
1312
ERR_INVALID_PACKAGE_CONFIG,
1413
} = require('internal/errors').codes;
15-
const { internalModuleReadJSON } = internalBinding('fs');
14+
const modulesBinding = internalBinding('modules');
1615
const { resolve, sep, toNamespacedPath } = require('path');
1716
const permission = require('internal/process/permission');
1817
const { kEmptyObject, setOwnProperty } = require('internal/util');
1918

2019
const { fileURLToPath, pathToFileURL } = require('internal/url');
2120

22-
const cache = new SafeMap();
23-
2421
let manifest;
2522

2623
/**
@@ -45,11 +42,7 @@ let manifest;
4542
* @returns {PackageConfig}
4643
*/
4744
function read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
48-
if (cache.has(jsonPath)) {
49-
return cache.get(jsonPath);
50-
}
51-
52-
const string = internalModuleReadJSON(
45+
const string = modulesBinding.readPackageJSON(
5346
toNamespacedPath(jsonPath),
5447
);
5548
const result = {
@@ -112,7 +105,6 @@ function read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
112105
manifest.assertIntegrity(jsonURL, string);
113106
}
114107
}
115-
cache.set(jsonPath, result);
116108
return result;
117109
}
118110

node.gyp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
'src/node_main_instance.cc',
113113
'src/node_messaging.cc',
114114
'src/node_metadata.cc',
115+
'src/node_modules.cc',
115116
'src/node_options.cc',
116117
'src/node_os.cc',
117118
'src/node_perf.cc',
@@ -234,6 +235,7 @@
234235
'src/node_messaging.h',
235236
'src/node_metadata.h',
236237
'src/node_mutex.h',
238+
'src/node_modules.h',
237239
'src/node_object_wrap.h',
238240
'src/node_options.h',
239241
'src/node_options-inl.h',

src/base_object_types.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ namespace node {
1717
V(blob_binding_data, BlobBindingData) \
1818
V(process_binding_data, process::BindingData) \
1919
V(timers_binding_data, timers::BindingData) \
20-
V(url_binding_data, url::BindingData)
20+
V(url_binding_data, url::BindingData) \
21+
V(modules_binding_data, modules::BindingData)
2122

2223
#define UNSERIALIZABLE_BINDING_TYPES(V) \
2324
V(http2_binding_data, http2::BindingData) \

src/node_binding.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
V(js_stream) \
5050
V(js_udp_wrap) \
5151
V(messaging) \
52+
V(modules) \
5253
V(module_wrap) \
5354
V(mksnapshot) \
5455
V(options) \

src/node_binding.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static_assert(static_cast<int>(NM_F_LINKED) ==
3838
V(encoding_binding) \
3939
V(fs) \
4040
V(mksnapshot) \
41+
V(modules) \
4142
V(timers) \
4243
V(process_methods) \
4344
V(performance) \

src/node_external_reference.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class ExternalReferenceRegistry {
100100
V(messaging) \
101101
V(mksnapshot) \
102102
V(module_wrap) \
103+
V(modules) \
103104
V(options) \
104105
V(os) \
105106
V(performance) \

src/node_file.cc

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,68 +1050,6 @@ static void ExistsSync(const FunctionCallbackInfo<Value>& args) {
10501050
args.GetReturnValue().Set(err == 0);
10511051
}
10521052

1053-
// Used to speed up module loading. Returns an array [string, boolean]
1054-
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
1055-
Environment* env = Environment::GetCurrent(args);
1056-
Isolate* isolate = env->isolate();
1057-
uv_loop_t* loop = env->event_loop();
1058-
1059-
CHECK(args[0]->IsString());
1060-
node::Utf8Value path(isolate, args[0]);
1061-
THROW_IF_INSUFFICIENT_PERMISSIONS(
1062-
env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
1063-
1064-
if (strlen(*path) != path.length()) {
1065-
return; // Contains a nul byte.
1066-
}
1067-
uv_fs_t open_req;
1068-
const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
1069-
uv_fs_req_cleanup(&open_req);
1070-
1071-
if (fd < 0) {
1072-
return;
1073-
}
1074-
1075-
auto defer_close = OnScopeLeave([fd, loop]() {
1076-
uv_fs_t close_req;
1077-
CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
1078-
uv_fs_req_cleanup(&close_req);
1079-
});
1080-
1081-
const size_t kBlockSize = 32 << 10;
1082-
std::vector<char> chars;
1083-
int64_t offset = 0;
1084-
ssize_t numchars;
1085-
do {
1086-
const size_t start = chars.size();
1087-
chars.resize(start + kBlockSize);
1088-
1089-
uv_buf_t buf;
1090-
buf.base = &chars[start];
1091-
buf.len = kBlockSize;
1092-
1093-
uv_fs_t read_req;
1094-
numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
1095-
uv_fs_req_cleanup(&read_req);
1096-
1097-
if (numchars < 0) {
1098-
return;
1099-
}
1100-
offset += numchars;
1101-
} while (static_cast<size_t>(numchars) == kBlockSize);
1102-
1103-
size_t start = 0;
1104-
if (offset >= 3 && 0 == memcmp(chars.data(), "\xEF\xBB\xBF", 3)) {
1105-
start = 3; // Skip UTF-8 BOM.
1106-
}
1107-
const size_t size = offset - start;
1108-
1109-
args.GetReturnValue().Set(
1110-
String::NewFromUtf8(
1111-
isolate, &chars[start], v8::NewStringType::kNormal, size)
1112-
.ToLocalChecked());
1113-
}
1114-
11151053
// Used to speed up module loading. Returns 0 if the path refers to
11161054
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
11171055
// The speedup comes from not creating thousands of Stat and Error objects.
@@ -3255,7 +3193,6 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
32553193
SetMethod(isolate, target, "rmdir", RMDir);
32563194
SetMethod(isolate, target, "mkdir", MKDir);
32573195
SetMethod(isolate, target, "readdir", ReadDir);
3258-
SetMethod(isolate, target, "internalModuleReadJSON", InternalModuleReadJSON);
32593196
SetMethod(isolate, target, "internalModuleStat", InternalModuleStat);
32603197
SetMethod(isolate, target, "stat", Stat);
32613198
SetMethod(isolate, target, "lstat", LStat);
@@ -3375,7 +3312,6 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
33753312
registry->Register(RMDir);
33763313
registry->Register(MKDir);
33773314
registry->Register(ReadDir);
3378-
registry->Register(InternalModuleReadJSON);
33793315
registry->Register(InternalModuleStat);
33803316
registry->Register(Stat);
33813317
registry->Register(LStat);

src/node_modules.cc

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#include "node_modules.h"
2+
#include "base_object-inl.h"
3+
#include "node_errors.h"
4+
#include "node_external_reference.h"
5+
#include "util-inl.h"
6+
#include "v8-fast-api-calls.h"
7+
#include "v8.h"
8+
9+
namespace node {
10+
namespace modules {
11+
12+
using v8::CFunction;
13+
using v8::Context;
14+
using v8::FastOneByteString;
15+
using v8::FunctionCallbackInfo;
16+
using v8::HandleScope;
17+
using v8::Isolate;
18+
using v8::Local;
19+
using v8::MaybeLocal;
20+
using v8::NewStringType;
21+
using v8::Object;
22+
using v8::ObjectTemplate;
23+
using v8::String;
24+
using v8::Value;
25+
26+
void BindingData::MemoryInfo(MemoryTracker* tracker) const {
27+
tracker->TrackField("package_json_files", package_json_files_);
28+
}
29+
30+
BindingData::BindingData(Realm* realm, v8::Local<v8::Object> object)
31+
: SnapshotableObject(realm, object, type_int) {
32+
package_json_files_ =
33+
v8::Global<v8::Map>(realm->isolate(), v8::Map::New(realm->isolate()));
34+
object
35+
->Set(realm->context(),
36+
FIXED_ONE_BYTE_STRING(realm->isolate(), "packageJsonFiles"),
37+
package_json_files_.Get(realm->isolate()))
38+
.Check();
39+
40+
package_json_files_.SetWeak();
41+
}
42+
43+
bool BindingData::PrepareForSerialization(v8::Local<v8::Context> context,
44+
v8::SnapshotCreator* creator) {
45+
package_json_files_.Reset();
46+
// Return true because we need to maintain the reference to the binding from
47+
// JS land.
48+
return true;
49+
}
50+
51+
InternalFieldInfoBase* BindingData::Serialize(int index) {
52+
DCHECK_IS_SNAPSHOT_SLOT(index);
53+
InternalFieldInfo* info =
54+
InternalFieldInfoBase::New<InternalFieldInfo>(type());
55+
return info;
56+
}
57+
58+
void BindingData::Deserialize(v8::Local<v8::Context> context,
59+
v8::Local<v8::Object> holder,
60+
int index,
61+
InternalFieldInfoBase* info) {
62+
DCHECK_IS_SNAPSHOT_SLOT(index);
63+
v8::HandleScope scope(context->GetIsolate());
64+
Realm* realm = Realm::GetCurrent(context);
65+
BindingData* binding = realm->AddBindingData<BindingData>(holder);
66+
CHECK_NOT_NULL(binding);
67+
}
68+
69+
void BindingData::ReadPackageJSON(const FunctionCallbackInfo<Value>& args) {
70+
CHECK_GE(args.Length(), 1);
71+
CHECK(args[0]->IsString());
72+
73+
Realm* realm = Realm::GetCurrent(args);
74+
auto isolate = realm->isolate();
75+
auto env = realm->env();
76+
auto context = realm->context();
77+
auto binding_data = realm->GetBindingData<BindingData>();
78+
auto package_json_files_ = binding_data->package_json_files_.Get(isolate);
79+
80+
Utf8Value path(isolate, args[0]);
81+
THROW_IF_INSUFFICIENT_PERMISSIONS(
82+
env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
83+
84+
if (strlen(*path) != path.length()) {
85+
return; // Contains a nul byte.
86+
}
87+
88+
Local<Value> cache_key =
89+
ToV8Value(context, path.ToStringView(), isolate).ToLocalChecked();
90+
MaybeLocal<Value> maybe_existing =
91+
package_json_files_->Get(context, cache_key);
92+
Local<Value> existing_value;
93+
if (maybe_existing.ToLocal(&existing_value) && existing_value->IsString()) {
94+
return args.GetReturnValue().Set(existing_value);
95+
}
96+
97+
uv_fs_t open_req;
98+
const int fd = uv_fs_open(nullptr, &open_req, *path, O_RDONLY, 0, nullptr);
99+
uv_fs_req_cleanup(&open_req);
100+
101+
if (fd < 0) {
102+
return;
103+
}
104+
105+
auto defer_close = OnScopeLeave([fd]() {
106+
uv_fs_t close_req;
107+
CHECK_EQ(0, uv_fs_close(nullptr, &close_req, fd, nullptr));
108+
uv_fs_req_cleanup(&close_req);
109+
});
110+
111+
const size_t kBlockSize = 32 << 10;
112+
std::vector<char> chars;
113+
int64_t offset = 0;
114+
ssize_t numchars;
115+
do {
116+
const size_t start = chars.size();
117+
chars.resize(start + kBlockSize);
118+
119+
uv_buf_t buf;
120+
buf.base = &chars[start];
121+
buf.len = kBlockSize;
122+
123+
uv_fs_t read_req;
124+
numchars = uv_fs_read(nullptr, &read_req, fd, &buf, 1, offset, nullptr);
125+
uv_fs_req_cleanup(&read_req);
126+
127+
if (numchars < 0) {
128+
return;
129+
}
130+
offset += numchars;
131+
} while (static_cast<size_t>(numchars) == kBlockSize);
132+
133+
size_t start = 0;
134+
if (offset >= 3 && 0 == memcmp(chars.data(), "\xEF\xBB\xBF", 3)) {
135+
start = 3; // Skip UTF-8 BOM.
136+
}
137+
138+
auto content =
139+
ToV8Value(
140+
context, std::string_view(&chars[start], offset - start), isolate)
141+
.ToLocalChecked();
142+
USE(package_json_files_->Set(context, cache_key, content));
143+
args.GetReturnValue().Set(content);
144+
}
145+
146+
void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
147+
Local<ObjectTemplate> target) {
148+
Isolate* isolate = isolate_data->isolate();
149+
SetMethod(isolate, target, "readPackageJSON", ReadPackageJSON);
150+
}
151+
152+
void BindingData::CreatePerContextProperties(Local<Object> target,
153+
Local<Value> unused,
154+
Local<Context> context,
155+
void* priv) {
156+
Realm* realm = Realm::GetCurrent(context);
157+
realm->AddBindingData<BindingData>(target);
158+
}
159+
160+
void BindingData::RegisterExternalReferences(
161+
ExternalReferenceRegistry* registry) {
162+
registry->Register(ReadPackageJSON);
163+
}
164+
165+
} // namespace modules
166+
} // namespace node
167+
168+
NODE_BINDING_CONTEXT_AWARE_INTERNAL(
169+
modules, node::modules::BindingData::CreatePerContextProperties)
170+
NODE_BINDING_PER_ISOLATE_INIT(
171+
modules, node::modules::BindingData::CreatePerIsolateProperties)
172+
NODE_BINDING_EXTERNAL_REFERENCE(
173+
modules, node::modules::BindingData::RegisterExternalReferences)

0 commit comments

Comments
 (0)