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: always compile and store code cache for native modules · nodejs/node@ee461fe

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • lib/internal/bootstrap
    • cache.js
  • src
    • node.cc
    • node_binding.cc
    • node_internals.h
    • node_native_module.cc
    • node_native_module.h
  • test/code-cache
    • test-code-cache.js
  • tools
    • generate_code_cache.js
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎lib/internal/bootstrap/cache.js‎

Copy file name to clipboardExpand all lines: lib/internal/bootstrap/cache.js
+5-2Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
// cannot be tampered with even with --expose-internals.
77

88
const { NativeModule } = require('internal/bootstrap/loaders');
9-
const { source, compileCodeCache } = internalBinding('native_module');
9+
const {
10+
source, getCodeCache, compileFunction
11+
} = internalBinding('native_module');
1012
const { hasTracing } = process.binding('config');
1113

1214
const depsModule = Object.keys(source).filter(
@@ -70,6 +72,7 @@ module.exports = {
7072
(key) => !cannotUseCache.includes(key)
7173
),
7274
getSource(id) { return source[id]; },
73-
getCodeCache: compileCodeCache,
75+
getCodeCache,
76+
compileFunction,
7477
cannotUseCache
7578
};
Collapse file

‎src/node.cc‎

Copy file name to clipboardExpand all lines: src/node.cc
+2-4Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ typedef int mode_t;
110110

111111
namespace node {
112112

113-
using native_module::NativeModuleLoader;
114113
using options_parser::kAllowedInEnvironment;
115114
using options_parser::kDisallowedInEnvironment;
116115
using v8::Array;
@@ -162,7 +161,6 @@ double prog_start_time;
162161
Mutex per_process_opts_mutex;
163162
std::shared_ptr<PerProcessOptions> per_process_opts {
164163
new PerProcessOptions() };
165-
NativeModuleLoader per_process_loader;
166164
static Mutex node_isolate_mutex;
167165
static Isolate* node_isolate;
168166

@@ -1191,7 +1189,7 @@ static MaybeLocal<Value> ExecuteBootstrapper(
11911189
const char* id,
11921190
std::vector<Local<String>>* parameters,
11931191
std::vector<Local<Value>>* arguments) {
1194-
MaybeLocal<Value> ret = per_process_loader.CompileAndCall(
1192+
MaybeLocal<Value> ret = per_process::native_module_loader.CompileAndCall(
11951193
env->context(), id, parameters, arguments, env);
11961194

11971195
// If there was an error during bootstrap then it was either handled by the
@@ -1908,7 +1906,7 @@ Local<Context> NewContext(Isolate* isolate,
19081906
std::vector<Local<String>> parameters = {
19091907
FIXED_ONE_BYTE_STRING(isolate, "global")};
19101908
std::vector<Local<Value>> arguments = {context->Global()};
1911-
MaybeLocal<Value> result = per_process_loader.CompileAndCall(
1909+
MaybeLocal<Value> result = per_process::native_module_loader.CompileAndCall(
19121910
context, "internal/per_context", &parameters, &arguments, nullptr);
19131911
if (result.IsEmpty()) {
19141912
// Execution failed during context creation.
Collapse file

‎src/node_binding.cc‎

Copy file name to clipboardExpand all lines: src/node_binding.cc
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,13 +389,14 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
389389
exports->SetPrototype(env->context(), Null(env->isolate())).FromJust());
390390
DefineConstants(env->isolate(), exports);
391391
} else if (!strcmp(*module_v, "natives")) {
392-
exports = per_process_loader.GetSourceObject(env->context());
392+
exports = per_process::native_module_loader.GetSourceObject(env->context());
393393
// Legacy feature: process.binding('natives').config contains stringified
394394
// config.gypi
395395
CHECK(exports
396396
->Set(env->context(),
397397
env->config_string(),
398-
per_process_loader.GetConfigString(env->isolate()))
398+
per_process::native_module_loader.GetConfigString(
399+
env->isolate()))
399400
.FromJust());
400401
} else {
401402
return ThrowIfNoSuchModule(env, *module_v);
Collapse file

‎src/node_internals.h‎

Copy file name to clipboardExpand all lines: src/node_internals.h
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ extern bool v8_initialized;
9191

9292
extern Mutex per_process_opts_mutex;
9393
extern std::shared_ptr<PerProcessOptions> per_process_opts;
94-
extern native_module::NativeModuleLoader per_process_loader;
9594

9695
// Forward declaration
9796
class Environment;
Collapse file

‎src/node_native_module.cc‎

Copy file name to clipboardExpand all lines: src/node_native_module.cc
+85-90Lines changed: 85 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
#include "node_internals.h"
44

55
namespace node {
6+
7+
namespace per_process {
8+
native_module::NativeModuleLoader native_module_loader;
9+
} // namespace per_process
10+
611
namespace native_module {
712

813
using v8::Array;
@@ -78,13 +83,14 @@ void NativeModuleLoader::GetCacheUsage(
7883
void NativeModuleLoader::SourceObjectGetter(
7984
Local<Name> property, const PropertyCallbackInfo<Value>& info) {
8085
Local<Context> context = info.GetIsolate()->GetCurrentContext();
81-
info.GetReturnValue().Set(per_process_loader.GetSourceObject(context));
86+
info.GetReturnValue().Set(
87+
per_process::native_module_loader.GetSourceObject(context));
8288
}
8389

8490
void NativeModuleLoader::ConfigStringGetter(
8591
Local<Name> property, const PropertyCallbackInfo<Value>& info) {
8692
info.GetReturnValue().Set(
87-
per_process_loader.GetConfigString(info.GetIsolate()));
93+
per_process::native_module_loader.GetConfigString(info.GetIsolate()));
8894
}
8995

9096
Local<Object> NativeModuleLoader::GetSourceObject(
@@ -96,41 +102,62 @@ Local<String> NativeModuleLoader::GetConfigString(Isolate* isolate) const {
96102
return config_.ToStringChecked(isolate);
97103
}
98104

99-
Local<String> NativeModuleLoader::GetSource(Isolate* isolate,
100-
const char* id) const {
101-
const auto it = source_.find(id);
102-
CHECK_NE(it, source_.end());
103-
return it->second.ToStringChecked(isolate);
104-
}
105-
106105
NativeModuleLoader::NativeModuleLoader() : config_(GetConfig()) {
107106
LoadJavaScriptSource();
108107
LoadCodeCache();
109108
}
110109

111-
void NativeModuleLoader::CompileCodeCache(
112-
const FunctionCallbackInfo<Value>& args) {
110+
// This is supposed to be run only by the main thread in
111+
// tools/generate_code_cache.js
112+
void NativeModuleLoader::GetCodeCache(const FunctionCallbackInfo<Value>& args) {
113113
Environment* env = Environment::GetCurrent(args);
114+
Isolate* isolate = env->isolate();
115+
CHECK(env->is_main_thread());
116+
114117
CHECK(args[0]->IsString());
115-
node::Utf8Value id(env->isolate(), args[0].As<String>());
118+
node::Utf8Value id_v(isolate, args[0].As<String>());
119+
const char* id = *id_v;
116120

117-
// TODO(joyeecheung): allow compiling cache for bootstrapper by
118-
// switching on id
119-
MaybeLocal<Value> result =
120-
CompileAsModule(env, *id, CompilationResultType::kCodeCache);
121-
if (!result.IsEmpty()) {
122-
args.GetReturnValue().Set(result.ToLocalChecked());
121+
const NativeModuleLoader& loader = per_process::native_module_loader;
122+
MaybeLocal<Uint8Array> ret = loader.GetCodeCache(isolate, id);
123+
if (!ret.IsEmpty()) {
124+
args.GetReturnValue().Set(ret.ToLocalChecked());
123125
}
124126
}
125127

128+
// This is supposed to be run only by the main thread in
129+
// tools/generate_code_cache.js
130+
MaybeLocal<Uint8Array> NativeModuleLoader::GetCodeCache(Isolate* isolate,
131+
const char* id) const {
132+
EscapableHandleScope scope(isolate);
133+
Mutex::ScopedLock lock(code_cache_mutex_);
134+
135+
ScriptCompiler::CachedData* cached_data = nullptr;
136+
const auto it = code_cache_.find(id);
137+
if (it == code_cache_.end()) {
138+
// The module has not been compiled before.
139+
return MaybeLocal<Uint8Array>();
140+
}
141+
142+
cached_data = it->second.get();
143+
144+
MallocedBuffer<uint8_t> copied(cached_data->length);
145+
memcpy(copied.data, cached_data->data, cached_data->length);
146+
Local<ArrayBuffer> buf =
147+
ArrayBuffer::New(isolate,
148+
copied.release(),
149+
cached_data->length,
150+
ArrayBufferCreationMode::kInternalized);
151+
return scope.Escape(Uint8Array::New(buf, 0, cached_data->length));
152+
}
153+
126154
void NativeModuleLoader::CompileFunction(
127155
const FunctionCallbackInfo<Value>& args) {
128156
Environment* env = Environment::GetCurrent(args);
129157
CHECK(args[0]->IsString());
130158
node::Utf8Value id(env->isolate(), args[0].As<String>());
131159

132-
MaybeLocal<Value> result =
133-
CompileAsModule(env, *id, CompilationResultType::kFunction);
160+
MaybeLocal<Function> result = CompileAsModule(env, *id);
134161
if (!result.IsEmpty()) {
135162
args.GetReturnValue().Set(result.ToLocalChecked());
136163
}
@@ -145,57 +172,43 @@ MaybeLocal<Value> NativeModuleLoader::CompileAndCall(
145172
std::vector<Local<Value>>* arguments,
146173
Environment* optional_env) {
147174
Isolate* isolate = context->GetIsolate();
148-
MaybeLocal<Value> compiled = per_process_loader.LookupAndCompile(
149-
context, id, parameters, CompilationResultType::kFunction, nullptr);
175+
MaybeLocal<Function> compiled =
176+
per_process::native_module_loader.LookupAndCompile(
177+
context, id, parameters, nullptr);
150178
if (compiled.IsEmpty()) {
151-
return compiled;
179+
return MaybeLocal<Value>();
152180
}
153181
Local<Function> fn = compiled.ToLocalChecked().As<Function>();
154182
return fn->Call(
155183
context, v8::Null(isolate), arguments->size(), arguments->data());
156184
}
157185

158-
MaybeLocal<Value> NativeModuleLoader::CompileAsModule(
159-
Environment* env, const char* id, CompilationResultType result) {
186+
MaybeLocal<Function> NativeModuleLoader::CompileAsModule(Environment* env,
187+
const char* id) {
160188
std::vector<Local<String>> parameters = {env->exports_string(),
161189
env->require_string(),
162190
env->module_string(),
163191
env->process_string(),
164192
env->internal_binding_string()};
165-
return per_process_loader.LookupAndCompile(
166-
env->context(), id, &parameters, result, env);
167-
}
168-
169-
// Returns nullptr if there is no code cache corresponding to the id
170-
ScriptCompiler::CachedData* NativeModuleLoader::GetCachedData(
171-
const char* id) const {
172-
const auto it = per_process_loader.code_cache_.find(id);
173-
// This could be false if the module cannot be cached somehow.
174-
// See lib/internal/bootstrap/cache.js on the modules that cannot be cached
175-
if (it == per_process_loader.code_cache_.end()) {
176-
return nullptr;
177-
}
178-
179-
const uint8_t* code_cache_value = it->second.one_bytes_data();
180-
size_t code_cache_length = it->second.length();
181-
182-
return new ScriptCompiler::CachedData(code_cache_value, code_cache_length);
193+
return per_process::native_module_loader.LookupAndCompile(
194+
env->context(), id, &parameters, env);
183195
}
184196

185197
// Returns Local<Function> of the compiled module if return_code_cache
186198
// is false (we are only compiling the function).
187199
// Otherwise return a Local<Object> containing the cache.
188-
MaybeLocal<Value> NativeModuleLoader::LookupAndCompile(
200+
MaybeLocal<Function> NativeModuleLoader::LookupAndCompile(
189201
Local<Context> context,
190202
const char* id,
191203
std::vector<Local<String>>* parameters,
192-
CompilationResultType result_type,
193204
Environment* optional_env) {
194205
Isolate* isolate = context->GetIsolate();
195206
EscapableHandleScope scope(isolate);
196207
Local<Value> ret; // Used to convert to MaybeLocal before return
197208

198-
Local<String> source = GetSource(isolate, id);
209+
const auto source_it = source_.find(id);
210+
CHECK_NE(source_it, source_.end());
211+
Local<String> source = source_it->second.ToStringChecked(isolate);
199212

200213
std::string filename_s = id + std::string(".js");
201214
Local<String> filename =
@@ -204,31 +217,24 @@ MaybeLocal<Value> NativeModuleLoader::LookupAndCompile(
204217
Local<Integer> column_offset = Integer::New(isolate, 0);
205218
ScriptOrigin origin(filename, line_offset, column_offset);
206219

207-
bool use_cache = false;
208-
ScriptCompiler::CachedData* cached_data = nullptr;
220+
Mutex::ScopedLock lock(code_cache_mutex_);
209221

210-
// 1. We won't even check the existence of the cache if the binary is not
211-
// built with them.
212-
// 2. If we are generating code cache for tools/general_code_cache.js, we
213-
// are not going to use any cache ourselves.
214-
if (has_code_cache_ && result_type == CompilationResultType::kFunction) {
215-
cached_data = GetCachedData(id);
216-
if (cached_data != nullptr) {
217-
use_cache = true;
222+
ScriptCompiler::CachedData* cached_data = nullptr;
223+
{
224+
auto cache_it = code_cache_.find(id);
225+
if (cache_it != code_cache_.end()) {
226+
// Transfer ownership to ScriptCompiler::Source later.
227+
cached_data = cache_it->second.release();
228+
code_cache_.erase(cache_it);
218229
}
219230
}
220231

232+
const bool use_cache = cached_data != nullptr;
233+
ScriptCompiler::CompileOptions options =
234+
use_cache ? ScriptCompiler::kConsumeCodeCache
235+
: ScriptCompiler::kEagerCompile;
221236
ScriptCompiler::Source script_source(source, origin, cached_data);
222237

223-
ScriptCompiler::CompileOptions options;
224-
if (result_type == CompilationResultType::kCodeCache) {
225-
options = ScriptCompiler::kEagerCompile;
226-
} else if (use_cache) {
227-
options = ScriptCompiler::kConsumeCodeCache;
228-
} else {
229-
options = ScriptCompiler::kNoCompileOptions;
230-
}
231-
232238
MaybeLocal<Function> maybe_fun =
233239
ScriptCompiler::CompileFunctionInContext(context,
234240
&script_source,
@@ -244,10 +250,14 @@ MaybeLocal<Value> NativeModuleLoader::LookupAndCompile(
244250
// In the case of early errors, v8 is already capable of
245251
// decorating the stack for us - note that we use CompileFunctionInContext
246252
// so there is no need to worry about wrappers.
247-
return MaybeLocal<Value>();
253+
return MaybeLocal<Function>();
248254
}
249255

250256
Local<Function> fun = maybe_fun.ToLocalChecked();
257+
// XXX(joyeecheung): this bookkeeping is not exactly accurate because
258+
// it only starts after the Environment is created, so the per_context.js
259+
// will never be in any of these two sets, but the two sets are only for
260+
// testing anyway.
251261
if (use_cache) {
252262
if (optional_env != nullptr) {
253263
// This could happen when Node is run with any v8 flag, but
@@ -264,29 +274,15 @@ MaybeLocal<Value> NativeModuleLoader::LookupAndCompile(
264274
}
265275
}
266276

267-
if (result_type == CompilationResultType::kCodeCache) {
268-
std::unique_ptr<ScriptCompiler::CachedData> cached_data(
269-
ScriptCompiler::CreateCodeCacheForFunction(fun));
270-
CHECK_NE(cached_data, nullptr);
271-
size_t cached_data_length = cached_data->length;
272-
// Since we have no special allocator to create an ArrayBuffer
273-
// from a new'ed pointer, we will need to copy it - but this
274-
// code path is only run by the tooling that generates the code
275-
// cache to be bundled in the binary
276-
// so it should be fine.
277-
MallocedBuffer<uint8_t> copied(cached_data->length);
278-
memcpy(copied.data, cached_data->data, cached_data_length);
279-
Local<ArrayBuffer> buf =
280-
ArrayBuffer::New(isolate,
281-
copied.release(),
282-
cached_data_length,
283-
ArrayBufferCreationMode::kInternalized);
284-
ret = Uint8Array::New(buf, 0, cached_data_length);
285-
} else {
286-
ret = fun;
287-
}
277+
// Generate new cache for next compilation
278+
std::unique_ptr<ScriptCompiler::CachedData> new_cached_data(
279+
ScriptCompiler::CreateCodeCacheForFunction(fun));
280+
CHECK_NE(new_cached_data, nullptr);
288281

289-
return scope.Escape(ret);
282+
// The old entry should've been erased by now so we can just emplace
283+
code_cache_.emplace(id, std::move(new_cached_data));
284+
285+
return scope.Escape(fun);
290286
}
291287

292288
void NativeModuleLoader::Initialize(Local<Object> target,
@@ -320,8 +316,7 @@ void NativeModuleLoader::Initialize(Local<Object> target,
320316
target, "getCacheUsage", NativeModuleLoader::GetCacheUsage);
321317
env->SetMethod(
322318
target, "compileFunction", NativeModuleLoader::CompileFunction);
323-
env->SetMethod(
324-
target, "compileCodeCache", NativeModuleLoader::CompileCodeCache);
319+
env->SetMethod(target, "getCodeCache", NativeModuleLoader::GetCodeCache);
325320
// internalBinding('native_module') should be frozen
326321
target->SetIntegrityLevel(context, IntegrityLevel::kFrozen).FromJust();
327322
}

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.