summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoyee Cheung <joyeec9h3@gmail.com>2018-12-03 21:47:57 +0800
committerJoyee Cheung <joyeec9h3@gmail.com>2018-12-18 18:02:11 +0800
commit0858e5d9d8db085cb83b3f1f3f94ed6b550a7bc5 (patch)
tree23855a4a96c3101d99a121c9ff158b9bea912708
parentceb66352236240498a9263500c7bde74e58c71fa (diff)
downloadandroid-node-v8-0858e5d9d8db085cb83b3f1f3f94ed6b550a7bc5.tar.gz
android-node-v8-0858e5d9d8db085cb83b3f1f3f94ed6b550a7bc5.tar.bz2
android-node-v8-0858e5d9d8db085cb83b3f1f3f94ed6b550a7bc5.zip
src: always compile and store code cache for native modules
This patch changes the NativeModuleLoader to always try to find code cache for native modules when it compiles them, and always produce and store the code cache after compilation. The cache map is protected by a mutex and can be accessed by different threads - including the worker threads and the main thread. Hence any thread can reuse the code cache if the native module has already been compiled by another thread - in particular the cache of the bootstrappers and per_context.js will always be hit when a new thread is spun. This results in a ~6% startup overhead in the worst case (when only the main thread is launched without requiring any additional native module - it now needs to do the extra work of finding and storing caches), which balances out the recent improvements by moving the compilation to C++, but it also leads to a ~60% improvement in the best case (when a worker thread is spun and requires a lot of native modules thus hitting the cache compiled by the main thread). PR-URL: https://github.com/nodejs/node/pull/24950 Reviewed-By: Anna Henningsen <anna@addaleax.net>
-rw-r--r--lib/internal/bootstrap/cache.js7
-rw-r--r--src/node.cc6
-rw-r--r--src/node_binding.cc5
-rw-r--r--src/node_internals.h1
-rw-r--r--src/node_native_module.cc175
-rw-r--r--src/node_native_module.h47
-rw-r--r--test/code-cache/test-code-cache.js16
-rw-r--r--tools/generate_code_cache.js9
8 files changed, 138 insertions, 128 deletions
diff --git a/lib/internal/bootstrap/cache.js b/lib/internal/bootstrap/cache.js
index bc0a01cf67..725425b2ce 100644
--- a/lib/internal/bootstrap/cache.js
+++ b/lib/internal/bootstrap/cache.js
@@ -6,7 +6,9 @@
// cannot be tampered with even with --expose-internals.
const { NativeModule } = require('internal/bootstrap/loaders');
-const { source, compileCodeCache } = internalBinding('native_module');
+const {
+ source, getCodeCache, compileFunction
+} = internalBinding('native_module');
const { hasTracing } = process.binding('config');
const depsModule = Object.keys(source).filter(
@@ -69,6 +71,7 @@ module.exports = {
(key) => !cannotUseCache.includes(key)
),
getSource(id) { return source[id]; },
- getCodeCache: compileCodeCache,
+ getCodeCache,
+ compileFunction,
cannotUseCache
};
diff --git a/src/node.cc b/src/node.cc
index 37d0055fd5..d830b846c9 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -110,7 +110,6 @@ typedef int mode_t;
namespace node {
-using native_module::NativeModuleLoader;
using options_parser::kAllowedInEnvironment;
using options_parser::kDisallowedInEnvironment;
using v8::Array;
@@ -162,7 +161,6 @@ double prog_start_time;
Mutex per_process_opts_mutex;
std::shared_ptr<PerProcessOptions> per_process_opts {
new PerProcessOptions() };
-NativeModuleLoader per_process_loader;
static Mutex node_isolate_mutex;
static Isolate* node_isolate;
@@ -1187,7 +1185,7 @@ static MaybeLocal<Value> ExecuteBootstrapper(
const char* id,
std::vector<Local<String>>* parameters,
std::vector<Local<Value>>* arguments) {
- MaybeLocal<Value> ret = per_process_loader.CompileAndCall(
+ MaybeLocal<Value> ret = per_process::native_module_loader.CompileAndCall(
env->context(), id, parameters, arguments, env);
// If there was an error during bootstrap then it was either handled by the
@@ -1906,7 +1904,7 @@ Local<Context> NewContext(Isolate* isolate,
std::vector<Local<String>> parameters = {
FIXED_ONE_BYTE_STRING(isolate, "global")};
std::vector<Local<Value>> arguments = {context->Global()};
- MaybeLocal<Value> result = per_process_loader.CompileAndCall(
+ MaybeLocal<Value> result = per_process::native_module_loader.CompileAndCall(
context, "internal/per_context", &parameters, &arguments, nullptr);
if (result.IsEmpty()) {
// Execution failed during context creation.
diff --git a/src/node_binding.cc b/src/node_binding.cc
index bdfb74e274..4a47c744c2 100644
--- a/src/node_binding.cc
+++ b/src/node_binding.cc
@@ -411,13 +411,14 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
exports->SetPrototype(env->context(), Null(env->isolate())).FromJust());
DefineConstants(env->isolate(), exports);
} else if (!strcmp(*module_v, "natives")) {
- exports = per_process_loader.GetSourceObject(env->context());
+ exports = per_process::native_module_loader.GetSourceObject(env->context());
// Legacy feature: process.binding('natives').config contains stringified
// config.gypi
CHECK(exports
->Set(env->context(),
env->config_string(),
- per_process_loader.GetConfigString(env->isolate()))
+ per_process::native_module_loader.GetConfigString(
+ env->isolate()))
.FromJust());
} else {
return ThrowIfNoSuchModule(env, *module_v);
diff --git a/src/node_internals.h b/src/node_internals.h
index 6fe1d9a80a..d9a72a10a4 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -91,7 +91,6 @@ extern bool v8_initialized;
extern Mutex per_process_opts_mutex;
extern std::shared_ptr<PerProcessOptions> per_process_opts;
-extern native_module::NativeModuleLoader per_process_loader;
// Forward declaration
class Environment;
diff --git a/src/node_native_module.cc b/src/node_native_module.cc
index 98cc128b73..d7fa5798d0 100644
--- a/src/node_native_module.cc
+++ b/src/node_native_module.cc
@@ -3,6 +3,11 @@
#include "node_internals.h"
namespace node {
+
+namespace per_process {
+native_module::NativeModuleLoader native_module_loader;
+} // namespace per_process
+
namespace native_module {
using v8::Array;
@@ -78,13 +83,14 @@ void NativeModuleLoader::GetCacheUsage(
void NativeModuleLoader::SourceObjectGetter(
Local<Name> property, const PropertyCallbackInfo<Value>& info) {
Local<Context> context = info.GetIsolate()->GetCurrentContext();
- info.GetReturnValue().Set(per_process_loader.GetSourceObject(context));
+ info.GetReturnValue().Set(
+ per_process::native_module_loader.GetSourceObject(context));
}
void NativeModuleLoader::ConfigStringGetter(
Local<Name> property, const PropertyCallbackInfo<Value>& info) {
info.GetReturnValue().Set(
- per_process_loader.GetConfigString(info.GetIsolate()));
+ per_process::native_module_loader.GetConfigString(info.GetIsolate()));
}
Local<Object> NativeModuleLoader::GetSourceObject(
@@ -96,41 +102,62 @@ Local<String> NativeModuleLoader::GetConfigString(Isolate* isolate) const {
return config_.ToStringChecked(isolate);
}
-Local<String> NativeModuleLoader::GetSource(Isolate* isolate,
- const char* id) const {
- const auto it = source_.find(id);
- CHECK_NE(it, source_.end());
- return it->second.ToStringChecked(isolate);
-}
-
NativeModuleLoader::NativeModuleLoader() : config_(GetConfig()) {
LoadJavaScriptSource();
LoadCodeCache();
}
-void NativeModuleLoader::CompileCodeCache(
- const FunctionCallbackInfo<Value>& args) {
+// This is supposed to be run only by the main thread in
+// tools/generate_code_cache.js
+void NativeModuleLoader::GetCodeCache(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
+ Isolate* isolate = env->isolate();
+ CHECK(env->is_main_thread());
+
CHECK(args[0]->IsString());
- node::Utf8Value id(env->isolate(), args[0].As<String>());
+ node::Utf8Value id_v(isolate, args[0].As<String>());
+ const char* id = *id_v;
- // TODO(joyeecheung): allow compiling cache for bootstrapper by
- // switching on id
- MaybeLocal<Value> result =
- CompileAsModule(env, *id, CompilationResultType::kCodeCache);
- if (!result.IsEmpty()) {
- args.GetReturnValue().Set(result.ToLocalChecked());
+ const NativeModuleLoader& loader = per_process::native_module_loader;
+ MaybeLocal<Uint8Array> ret = loader.GetCodeCache(isolate, id);
+ if (!ret.IsEmpty()) {
+ args.GetReturnValue().Set(ret.ToLocalChecked());
}
}
+// This is supposed to be run only by the main thread in
+// tools/generate_code_cache.js
+MaybeLocal<Uint8Array> NativeModuleLoader::GetCodeCache(Isolate* isolate,
+ const char* id) const {
+ EscapableHandleScope scope(isolate);
+ Mutex::ScopedLock lock(code_cache_mutex_);
+
+ ScriptCompiler::CachedData* cached_data = nullptr;
+ const auto it = code_cache_.find(id);
+ if (it == code_cache_.end()) {
+ // The module has not been compiled before.
+ return MaybeLocal<Uint8Array>();
+ }
+
+ cached_data = it->second.get();
+
+ MallocedBuffer<uint8_t> copied(cached_data->length);
+ memcpy(copied.data, cached_data->data, cached_data->length);
+ Local<ArrayBuffer> buf =
+ ArrayBuffer::New(isolate,
+ copied.release(),
+ cached_data->length,
+ ArrayBufferCreationMode::kInternalized);
+ return scope.Escape(Uint8Array::New(buf, 0, cached_data->length));
+}
+
void NativeModuleLoader::CompileFunction(
const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsString());
node::Utf8Value id(env->isolate(), args[0].As<String>());
- MaybeLocal<Value> result =
- CompileAsModule(env, *id, CompilationResultType::kFunction);
+ MaybeLocal<Function> result = CompileAsModule(env, *id);
if (!result.IsEmpty()) {
args.GetReturnValue().Set(result.ToLocalChecked());
}
@@ -145,57 +172,43 @@ MaybeLocal<Value> NativeModuleLoader::CompileAndCall(
std::vector<Local<Value>>* arguments,
Environment* optional_env) {
Isolate* isolate = context->GetIsolate();
- MaybeLocal<Value> compiled = per_process_loader.LookupAndCompile(
- context, id, parameters, CompilationResultType::kFunction, nullptr);
+ MaybeLocal<Function> compiled =
+ per_process::native_module_loader.LookupAndCompile(
+ context, id, parameters, nullptr);
if (compiled.IsEmpty()) {
- return compiled;
+ return MaybeLocal<Value>();
}
Local<Function> fn = compiled.ToLocalChecked().As<Function>();
return fn->Call(
context, v8::Null(isolate), arguments->size(), arguments->data());
}
-MaybeLocal<Value> NativeModuleLoader::CompileAsModule(
- Environment* env, const char* id, CompilationResultType result) {
+MaybeLocal<Function> NativeModuleLoader::CompileAsModule(Environment* env,
+ const char* id) {
std::vector<Local<String>> parameters = {env->exports_string(),
env->require_string(),
env->module_string(),
env->process_string(),
env->internal_binding_string()};
- return per_process_loader.LookupAndCompile(
- env->context(), id, &parameters, result, env);
-}
-
-// Returns nullptr if there is no code cache corresponding to the id
-ScriptCompiler::CachedData* NativeModuleLoader::GetCachedData(
- const char* id) const {
- const auto it = per_process_loader.code_cache_.find(id);
- // This could be false if the module cannot be cached somehow.
- // See lib/internal/bootstrap/cache.js on the modules that cannot be cached
- if (it == per_process_loader.code_cache_.end()) {
- return nullptr;
- }
-
- const uint8_t* code_cache_value = it->second.one_bytes_data();
- size_t code_cache_length = it->second.length();
-
- return new ScriptCompiler::CachedData(code_cache_value, code_cache_length);
+ return per_process::native_module_loader.LookupAndCompile(
+ env->context(), id, &parameters, env);
}
// Returns Local<Function> of the compiled module if return_code_cache
// is false (we are only compiling the function).
// Otherwise return a Local<Object> containing the cache.
-MaybeLocal<Value> NativeModuleLoader::LookupAndCompile(
+MaybeLocal<Function> NativeModuleLoader::LookupAndCompile(
Local<Context> context,
const char* id,
std::vector<Local<String>>* parameters,
- CompilationResultType result_type,
Environment* optional_env) {
Isolate* isolate = context->GetIsolate();
EscapableHandleScope scope(isolate);
Local<Value> ret; // Used to convert to MaybeLocal before return
- Local<String> source = GetSource(isolate, id);
+ const auto source_it = source_.find(id);
+ CHECK_NE(source_it, source_.end());
+ Local<String> source = source_it->second.ToStringChecked(isolate);
std::string filename_s = id + std::string(".js");
Local<String> filename =
@@ -204,31 +217,24 @@ MaybeLocal<Value> NativeModuleLoader::LookupAndCompile(
Local<Integer> column_offset = Integer::New(isolate, 0);
ScriptOrigin origin(filename, line_offset, column_offset);
- bool use_cache = false;
- ScriptCompiler::CachedData* cached_data = nullptr;
+ Mutex::ScopedLock lock(code_cache_mutex_);
- // 1. We won't even check the existence of the cache if the binary is not
- // built with them.
- // 2. If we are generating code cache for tools/general_code_cache.js, we
- // are not going to use any cache ourselves.
- if (has_code_cache_ && result_type == CompilationResultType::kFunction) {
- cached_data = GetCachedData(id);
- if (cached_data != nullptr) {
- use_cache = true;
+ ScriptCompiler::CachedData* cached_data = nullptr;
+ {
+ auto cache_it = code_cache_.find(id);
+ if (cache_it != code_cache_.end()) {
+ // Transfer ownership to ScriptCompiler::Source later.
+ cached_data = cache_it->second.release();
+ code_cache_.erase(cache_it);
}
}
+ const bool use_cache = cached_data != nullptr;
+ ScriptCompiler::CompileOptions options =
+ use_cache ? ScriptCompiler::kConsumeCodeCache
+ : ScriptCompiler::kEagerCompile;
ScriptCompiler::Source script_source(source, origin, cached_data);
- ScriptCompiler::CompileOptions options;
- if (result_type == CompilationResultType::kCodeCache) {
- options = ScriptCompiler::kEagerCompile;
- } else if (use_cache) {
- options = ScriptCompiler::kConsumeCodeCache;
- } else {
- options = ScriptCompiler::kNoCompileOptions;
- }
-
MaybeLocal<Function> maybe_fun =
ScriptCompiler::CompileFunctionInContext(context,
&script_source,
@@ -244,10 +250,14 @@ MaybeLocal<Value> NativeModuleLoader::LookupAndCompile(
// In the case of early errors, v8 is already capable of
// decorating the stack for us - note that we use CompileFunctionInContext
// so there is no need to worry about wrappers.
- return MaybeLocal<Value>();
+ return MaybeLocal<Function>();
}
Local<Function> fun = maybe_fun.ToLocalChecked();
+ // XXX(joyeecheung): this bookkeeping is not exactly accurate because
+ // it only starts after the Environment is created, so the per_context.js
+ // will never be in any of these two sets, but the two sets are only for
+ // testing anyway.
if (use_cache) {
if (optional_env != nullptr) {
// This could happen when Node is run with any v8 flag, but
@@ -264,29 +274,15 @@ MaybeLocal<Value> NativeModuleLoader::LookupAndCompile(
}
}
- if (result_type == CompilationResultType::kCodeCache) {
- std::unique_ptr<ScriptCompiler::CachedData> cached_data(
- ScriptCompiler::CreateCodeCacheForFunction(fun));
- CHECK_NE(cached_data, nullptr);
- size_t cached_data_length = cached_data->length;
- // Since we have no special allocator to create an ArrayBuffer
- // from a new'ed pointer, we will need to copy it - but this
- // code path is only run by the tooling that generates the code
- // cache to be bundled in the binary
- // so it should be fine.
- MallocedBuffer<uint8_t> copied(cached_data->length);
- memcpy(copied.data, cached_data->data, cached_data_length);
- Local<ArrayBuffer> buf =
- ArrayBuffer::New(isolate,
- copied.release(),
- cached_data_length,
- ArrayBufferCreationMode::kInternalized);
- ret = Uint8Array::New(buf, 0, cached_data_length);
- } else {
- ret = fun;
- }
+ // Generate new cache for next compilation
+ std::unique_ptr<ScriptCompiler::CachedData> new_cached_data(
+ ScriptCompiler::CreateCodeCacheForFunction(fun));
+ CHECK_NE(new_cached_data, nullptr);
- return scope.Escape(ret);
+ // The old entry should've been erased by now so we can just emplace
+ code_cache_.emplace(id, std::move(new_cached_data));
+
+ return scope.Escape(fun);
}
void NativeModuleLoader::Initialize(Local<Object> target,
@@ -320,8 +316,7 @@ void NativeModuleLoader::Initialize(Local<Object> target,
target, "getCacheUsage", NativeModuleLoader::GetCacheUsage);
env->SetMethod(
target, "compileFunction", NativeModuleLoader::CompileFunction);
- env->SetMethod(
- target, "compileCodeCache", NativeModuleLoader::CompileCodeCache);
+ env->SetMethod(target, "getCodeCache", NativeModuleLoader::GetCodeCache);
// internalBinding('native_module') should be frozen
target->SetIntegrityLevel(context, IntegrityLevel::kFrozen).FromJust();
}
diff --git a/src/node_native_module.h b/src/node_native_module.h
index 54c5f388f7..2e5821c2cf 100644
--- a/src/node_native_module.h
+++ b/src/node_native_module.h
@@ -7,6 +7,7 @@
#include <set>
#include <string>
#include "env.h"
+#include "node_mutex.h"
#include "node_union_bytes.h"
#include "v8.h"
@@ -14,7 +15,9 @@ namespace node {
namespace native_module {
using NativeModuleRecordMap = std::map<std::string, UnionBytes>;
-using NativeModuleHashMap = std::map<std::string, std::string>;
+using NativeModuleCacheMap =
+ std::unordered_map<std::string,
+ std::unique_ptr<v8::ScriptCompiler::CachedData>>;
// The native (C++) side of the NativeModule in JS land, which
// handles compilation and caching of builtin modules (NativeModule)
@@ -25,16 +28,12 @@ using NativeModuleHashMap = std::map<std::string, std::string>;
// The instances of this class are per-process.
class NativeModuleLoader {
public:
- // kCodeCache indicates that the compilation result should be returned
- // as a Uint8Array, whereas kFunction indicates that the result should
- // be returned as a Function.
- // TODO(joyeecheung): it's possible to always produce code cache
- // on the main thread and consume them in worker threads, or just
- // share the cache among all the threads, although
- // we need to decide whether to do that even when workers are not used.
- enum class CompilationResultType { kCodeCache, kFunction };
-
NativeModuleLoader();
+ // TODO(joyeecheung): maybe we should make this a singleton, instead of
+ // putting it in per_process.
+ NativeModuleLoader(const NativeModuleLoader&) = delete;
+ NativeModuleLoader& operator=(const NativeModuleLoader&) = delete;
+
static void Initialize(v8::Local<v8::Object> target,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
@@ -43,8 +42,6 @@ class NativeModuleLoader {
// Returns config.gypi as a JSON string
v8::Local<v8::String> GetConfigString(v8::Isolate* isolate) const;
- v8::Local<v8::String> GetSource(v8::Isolate* isolate, const char* id) const;
-
// Run a script with JS source bundled inside the binary as if it's wrapped
// in a function called with a null receiver and arguments specified in C++.
// The returned value is empty if an exception is encountered.
@@ -68,8 +65,10 @@ class NativeModuleLoader {
static void ConfigStringGetter(
v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Value>& info);
- // Compile code cache for a specific native module
- static void CompileCodeCache(const v8::FunctionCallbackInfo<v8::Value>& args);
+ // Get code cache for a specific native module
+ static void GetCodeCache(const v8::FunctionCallbackInfo<v8::Value>& args);
+ v8::MaybeLocal<v8::Uint8Array> GetCodeCache(v8::Isolate* isolate,
+ const char* id) const;
// Compile a specific native module as a function
static void CompileFunction(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -82,30 +81,34 @@ class NativeModuleLoader {
// in node_code_cache_stub.cc
void LoadCodeCache(); // Loads data into code_cache_
- v8::ScriptCompiler::CachedData* GetCachedData(const char* id) const;
-
// Compile a script as a NativeModule that can be loaded via
// NativeModule.p.require in JS land.
- static v8::MaybeLocal<v8::Value> CompileAsModule(
- Environment* env, const char* id, CompilationResultType result_type);
+ static v8::MaybeLocal<v8::Function> CompileAsModule(Environment* env,
+ const char* id);
// For bootstrappers optional_env may be a nullptr.
// If an exception is encountered (e.g. source code contains
// syntax error), the returned value is empty.
- v8::MaybeLocal<v8::Value> LookupAndCompile(
+ v8::MaybeLocal<v8::Function> LookupAndCompile(
v8::Local<v8::Context> context,
const char* id,
std::vector<v8::Local<v8::String>>* parameters,
- CompilationResultType result_type,
Environment* optional_env);
- bool has_code_cache_ = false;
NativeModuleRecordMap source_;
- NativeModuleRecordMap code_cache_;
+ NativeModuleCacheMap code_cache_;
UnionBytes config_;
+
+ // Used to synchronize access to the code cache map
+ Mutex code_cache_mutex_;
};
} // namespace native_module
+
+namespace per_process {
+extern native_module::NativeModuleLoader native_module_loader;
+} // namespace per_process
+
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
diff --git a/test/code-cache/test-code-cache.js b/test/code-cache/test-code-cache.js
index 669e1367d6..367e72168a 100644
--- a/test/code-cache/test-code-cache.js
+++ b/test/code-cache/test-code-cache.js
@@ -43,11 +43,17 @@ const loadedModules = process.moduleLoadList
// are all compiled without cache and we are doing the bookkeeping right.
if (process.config.variables.node_code_cache_path === undefined) {
console.log('The binary is not configured with code cache');
- assert.deepStrictEqual(compiledWithCache, new Set());
-
- for (const key of loadedModules) {
- assert(compiledWithoutCache.has(key),
- `"${key}" should've been compiled without code cache`);
+ if (isMainThread) {
+ assert.deepStrictEqual(compiledWithCache, new Set());
+ for (const key of loadedModules) {
+ assert(compiledWithoutCache.has(key),
+ `"${key}" should've been compiled without code cache`);
+ }
+ } else {
+ // TODO(joyeecheung): create a list of modules whose cache can be shared
+ // from the main thread to the worker thread and check that their
+ // cache are hit
+ assert.notDeepStrictEqual(compiledWithCache, new Set());
}
} else {
console.log('The binary is configured with code cache');
diff --git a/tools/generate_code_cache.js b/tools/generate_code_cache.js
index 3e21743f2c..a434f640c2 100644
--- a/tools/generate_code_cache.js
+++ b/tools/generate_code_cache.js
@@ -9,6 +9,7 @@
const {
getCodeCache,
+ compileFunction,
cachableBuiltins
} = require('internal/bootstrap/cache');
@@ -57,10 +58,13 @@ function getInitalizer(key, cache) {
const defName = `${key.replace(/\//g, '_').replace(/-/g, '_')}_raw`;
const definition = `static const uint8_t ${defName}[] = {\n` +
`${cache.join(',')}\n};`;
+ const dataDef = 'std::make_unique<v8::ScriptCompiler::CachedData>(' +
+ `${defName}, static_cast<int>(arraysize(${defName})), ` +
+ 'policy)';
const initializer =
'code_cache_.emplace(\n' +
` "${key}",\n` +
- ` UnionBytes(${defName}, arraysize(${defName}))\n` +
+ ` ${dataDef}\n` +
');';
return {
definition, initializer
@@ -82,6 +86,7 @@ function lexical(a, b) {
}
for (const key of cachableBuiltins.sort(lexical)) {
+ compileFunction(key); // compile it
const cachedData = getCodeCache(key);
if (!isUint8Array(cachedData)) {
console.error(`Failed to generate code cache for '${key}'`);
@@ -110,7 +115,7 @@ namespace native_module {
${cacheDefinitions.join('\n\n')}
void NativeModuleLoader::LoadCodeCache() {
- has_code_cache_ = true;
+ auto policy = v8::ScriptCompiler::CachedData::BufferPolicy::BufferNotOwned;
${cacheInitializers.join('\n ')}
}