summaryrefslogtreecommitdiff
path: root/src/node_native_module.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/node_native_module.cc')
-rw-r--r--src/node_native_module.cc324
1 files changed, 162 insertions, 162 deletions
diff --git a/src/node_native_module.cc b/src/node_native_module.cc
index ea7fe9189a..11136a244c 100644
--- a/src/node_native_module.cc
+++ b/src/node_native_module.cc
@@ -1,13 +1,13 @@
#include "node_native_module.h"
-#include "node_code_cache.h"
#include "node_errors.h"
-#include "node_javascript.h"
+#include "node_internals.h"
namespace node {
namespace native_module {
using v8::Array;
using v8::ArrayBuffer;
+using v8::ArrayBufferCreationMode;
using v8::Context;
using v8::EscapableHandleScope;
using v8::Function;
@@ -25,94 +25,107 @@ using v8::ScriptCompiler;
using v8::ScriptOrigin;
using v8::Set;
using v8::String;
-using v8::TryCatch;
using v8::Uint8Array;
using v8::Value;
-void NativeModule::GetNatives(Environment* env, Local<Object> exports) {
- DefineJavaScript(env, exports);
+// TODO(joyeecheung): make these more general and put them into util.h
+Local<Object> MapToObject(Local<Context> context,
+ const NativeModuleRecordMap& in) {
+ Isolate* isolate = context->GetIsolate();
+ Local<Object> out = Object::New(isolate);
+ for (auto const& x : in) {
+ Local<String> key = OneByteString(isolate, x.first.c_str(), x.first.size());
+ out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust();
+ }
+ return out;
+}
+
+Local<Set> ToJsSet(Local<Context> context,
+ const std::set<std::string>& in) {
+ Isolate* isolate = context->GetIsolate();
+ Local<Set> out = Set::New(isolate);
+ for (auto const& x : in) {
+ out->Add(context, OneByteString(isolate, x.c_str(), x.size()))
+ .ToLocalChecked();
+ }
+ return out;
}
-void NativeModule::LoadBindings(Environment* env) {
- // TODO(joyeecheung): put the static values into a
- // std::map<std::string, const uint8_t*> instead of a v8::Object,
- // because here they are only looked up from the C++ side
- // (except in process.binding('natives') which we don't use)
- // so there is little value to put them in a v8::Object upfront.
- // Moreover, a std::map lookup should be faster than a lookup on
- // an V8 Object in dictionary mode.
+void NativeModuleLoader::GetCacheUsage(
+ const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();
Local<Context> context = env->context();
- Local<Value> null = Null(isolate);
-
- Local<Object> native_modules_source = Object::New(isolate);
- CHECK(native_modules_source->SetPrototype(context, null).FromJust());
- DefineJavaScript(env, native_modules_source);
- native_modules_source->SetIntegrityLevel(context, IntegrityLevel::kFrozen)
+ Local<Object> result = Object::New(isolate);
+ result
+ ->Set(env->context(),
+ OneByteString(isolate, "compiledWithCache"),
+ ToJsSet(context, env->native_modules_with_cache))
.FromJust();
- env->set_native_modules_source(native_modules_source);
-
- Local<Object> native_modules_source_hash = Object::New(isolate);
- CHECK(native_modules_source_hash->SetPrototype(context, null).FromJust());
- DefineJavaScriptHash(env, native_modules_source_hash);
- native_modules_source_hash
- ->SetIntegrityLevel(context, IntegrityLevel::kFrozen)
+ result
+ ->Set(env->context(),
+ OneByteString(isolate, "compiledWithoutCache"),
+ ToJsSet(context, env->native_modules_without_cache))
.FromJust();
- env->set_native_modules_source_hash(native_modules_source_hash);
+ args.GetReturnValue().Set(result);
+}
- Local<Object> native_modules_code_cache = Object::New(isolate);
- CHECK(native_modules_code_cache->SetPrototype(context, null).FromJust());
- DefineCodeCache(env, native_modules_code_cache);
- native_modules_code_cache->SetIntegrityLevel(context, IntegrityLevel::kFrozen)
- .FromJust();
- env->set_native_modules_code_cache(native_modules_code_cache);
+void NativeModuleLoader::GetSourceObject(
+ const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ args.GetReturnValue().Set(per_process_loader.GetSourceObject(env->context()));
+}
- Local<Object> native_modules_code_cache_hash = Object::New(isolate);
- CHECK(native_modules_code_cache_hash->SetPrototype(context, null).FromJust());
- DefineCodeCacheHash(env, native_modules_code_cache_hash);
- native_modules_code_cache_hash
- ->SetIntegrityLevel(context, IntegrityLevel::kFrozen)
- .FromJust();
- env->set_native_modules_code_cache_hash(native_modules_code_cache_hash);
+Local<Object> NativeModuleLoader::GetSourceObject(
+ Local<Context> context) const {
+ return MapToObject(context, source_);
+}
+
+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);
+}
- env->set_native_modules_with_cache(Set::New(isolate));
- env->set_native_modules_without_cache(Set::New(isolate));
+NativeModuleLoader::NativeModuleLoader() {
+ LoadJavaScriptSource();
+ LoadJavaScriptHash();
+ LoadCodeCache();
+ LoadCodeCacheHash();
}
-void NativeModule::CompileCodeCache(const FunctionCallbackInfo<Value>& args) {
+void NativeModuleLoader::CompileCodeCache(
+ const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsString());
- Local<String> id = args[0].As<String>();
+ node::Utf8Value id(env->isolate(), args[0].As<String>());
- Local<Value> result = CompileAsModule(env, id, true);
+ // TODO(joyeecheung): allow compiling cache for bootstrapper by
+ // switching on id
+ Local<Value> result = CompileAsModule(env, *id, true);
if (!result.IsEmpty()) {
args.GetReturnValue().Set(result);
}
}
-void NativeModule::CompileFunction(const FunctionCallbackInfo<Value>& args) {
+void NativeModuleLoader::CompileFunction(
+ const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsString());
- Local<String> id = args[0].As<String>();
-
- Local<Value> result = CompileAsModule(env, id, false);
+ node::Utf8Value id(env->isolate(), args[0].As<String>());
+ Local<Value> result = CompileAsModule(env, *id, false);
if (!result.IsEmpty()) {
args.GetReturnValue().Set(result);
}
}
-Local<Value> NativeModule::CompileAsModule(Environment* env,
- Local<String> id,
- bool produce_code_cache) {
- Local<String> parameters[] = {env->exports_string(),
- env->require_string(),
- env->module_string(),
- env->process_string(),
- env->internal_binding_string()};
-
- return Compile(
- env, id, parameters, arraysize(parameters), produce_code_cache);
+Local<Value> NativeModuleLoader::CompileAsModule(Environment* env,
+ const char* id,
+ bool produce_code_cache) {
+ return per_process_loader.LookupAndCompile(
+ env->context(), id, produce_code_cache, env);
}
// Currently V8 only checks that the length of the source code is the
@@ -139,30 +152,25 @@ Local<Value> NativeModule::CompileAsModule(Environment* env,
// early in the bootstrap process so it should be easy to detect and fix.
// Returns nullptr if there is no code cache corresponding to the id
-ScriptCompiler::CachedData* GetCachedData(Environment* env, Local<String> id) {
- HandleScope scope(env->isolate());
- Local<Context> context = env->context();
-
- Local<Value> result =
- env->native_modules_code_cache()->Get(context, id).ToLocalChecked();
+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 (result->IsUndefined()) {
+ if (it == per_process_loader.code_cache_.end()) {
return nullptr;
}
- CHECK(result->IsUint8Array());
- Local<Uint8Array> code_cache = result.As<Uint8Array>();
+ const uint8_t* code_cache_value = it->second.one_bytes_data();
+ size_t code_cache_length = it->second.length();
- result =
- env->native_modules_code_cache_hash()->Get(context, id).ToLocalChecked();
- CHECK(result->IsString());
- Local<String> code_cache_hash = result.As<String>();
+ const auto it2 = code_cache_hash_.find(id);
+ CHECK_NE(it2, code_cache_hash_.end());
+ const std::string& code_cache_hash_value = it2->second;
- result =
- env->native_modules_source_hash()->Get(context, id).ToLocalChecked();
- CHECK(result->IsString());
- Local<String> source_hash = result.As<String>();
+ const auto it3 = source_hash_.find(id);
+ CHECK_NE(it3, source_hash_.end());
+ const std::string& source_hash_value = it3->second;
// It may fail when any of the inputs of the `node_js2c` target in
// node.gyp is modified but the tools/generate_code_cache.js
@@ -170,33 +178,26 @@ ScriptCompiler::CachedData* GetCachedData(Environment* env, Local<String> id) {
// FIXME(joyeecheung): Figure out how to resolve the dependency issue.
// When the code cache was introduced we were at a point where refactoring
// node.gyp may not be worth the effort.
- CHECK(code_cache_hash->StrictEquals(source_hash));
+ CHECK_EQ(code_cache_hash_value, source_hash_value);
- ArrayBuffer::Contents contents = code_cache->Buffer()->GetContents();
- uint8_t* data = static_cast<uint8_t*>(contents.Data());
- return new ScriptCompiler::CachedData(data + code_cache->ByteOffset(),
- code_cache->ByteLength());
+ return new ScriptCompiler::CachedData(code_cache_value, code_cache_length);
}
// Returns Local<Function> of the compiled module if produce_code_cache
// is false (we are only compiling the function).
// Otherwise return a Local<Object> containing the cache.
-Local<Value> NativeModule::Compile(Environment* env,
- Local<String> id,
- Local<String> parameters[],
- size_t parameters_count,
- bool produce_code_cache) {
- EscapableHandleScope scope(env->isolate());
- Local<Context> context = env->context();
- Isolate* isolate = env->isolate();
+Local<Value> NativeModuleLoader::LookupAndCompile(Local<Context> context,
+ const char* id,
+ bool produce_code_cache,
+ Environment* optional_env) {
+ Isolate* isolate = context->GetIsolate();
+ EscapableHandleScope scope(isolate);
- Local<Value> result =
- env->native_modules_source()->Get(context, id).ToLocalChecked();
- CHECK(result->IsString());
- Local<String> source = result.As<String>();
+ Local<String> source = GetSource(isolate, id);
+ std::string filename_s = id + std::string(".js");
Local<String> filename =
- String::Concat(isolate, id, FIXED_ONE_BYTE_STRING(isolate, ".js"));
+ OneByteString(isolate, filename_s.c_str(), filename_s.size());
Local<Integer> line_offset = Integer::New(isolate, 0);
Local<Integer> column_offset = Integer::New(isolate, 0);
ScriptOrigin origin(filename, line_offset, column_offset);
@@ -208,8 +209,8 @@ Local<Value> NativeModule::Compile(Environment* env,
// 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 (native_module_has_code_cache && !produce_code_cache) {
- cached_data = GetCachedData(env, id);
+ if (has_code_cache_ && !produce_code_cache) {
+ cached_data = GetCachedData(id);
if (cached_data != nullptr) {
use_cache = true;
}
@@ -226,35 +227,55 @@ Local<Value> NativeModule::Compile(Environment* env,
options = ScriptCompiler::kNoCompileOptions;
}
- MaybeLocal<Function> maybe_fun =
- ScriptCompiler::CompileFunctionInContext(context,
- &script_source,
- parameters_count,
- parameters,
- 0,
- nullptr,
- options);
+ MaybeLocal<Function> maybe_fun;
+ // Currently we assume if Environment is ready, then we must be compiling
+ // native modules instead of bootstrappers.
+ if (optional_env != nullptr) {
+ Local<String> parameters[] = {optional_env->exports_string(),
+ optional_env->require_string(),
+ optional_env->module_string(),
+ optional_env->process_string(),
+ optional_env->internal_binding_string()};
+ maybe_fun = ScriptCompiler::CompileFunctionInContext(context,
+ &script_source,
+ arraysize(parameters),
+ parameters,
+ 0,
+ nullptr,
+ options);
+ } else {
+ // Until we migrate bootstrappers compilations here this is unreachable
+ // TODO(joyeecheung): it should be possible to generate the argument names
+ // from some special comments for the bootstrapper case.
+ // Note that for bootstrappers we may not be able to get the argument
+ // names as env->some_string() because we might be compiling before
+ // those strings are initialized.
+ UNREACHABLE();
+ }
- TryCatch try_catch(isolate);
Local<Function> fun;
// This could fail when there are early errors in the native modules,
// e.g. the syntax errors
if (maybe_fun.IsEmpty() || !maybe_fun.ToLocal(&fun)) {
- DecorateErrorStack(env, try_catch);
- try_catch.ReThrow();
+ // 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 scope.Escape(Local<Value>());
}
if (use_cache) {
- // If the cache is rejected, something must be wrong with the build
- // and we should just crash.
- CHECK(!script_source.GetCachedData()->rejected);
- if (env->native_modules_with_cache()->Add(context, id).IsEmpty()) {
- return scope.Escape(Local<Value>());
+ if (optional_env != nullptr) {
+ // This could happen when Node is run with any v8 flag, but
+ // the cache is not generated with one
+ if (script_source.GetCachedData()->rejected) {
+ optional_env->native_modules_without_cache.insert(id);
+ } else {
+ optional_env->native_modules_with_cache.insert(id);
+ }
}
} else {
- if (env->native_modules_without_cache()->Add(context, id).IsEmpty()) {
- return scope.Escape(Local<Value>());
+ if (optional_env != nullptr) {
+ optional_env->native_modules_without_cache.insert(id);
}
}
@@ -262,59 +283,38 @@ Local<Value> NativeModule::Compile(Environment* env,
std::unique_ptr<ScriptCompiler::CachedData> cached_data(
ScriptCompiler::CreateCodeCacheForFunction(fun));
CHECK_NE(cached_data, nullptr);
- char* data =
- reinterpret_cast<char*>(const_cast<uint8_t*>(cached_data->data));
-
- // Since we have no API to create a buffer 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
+ 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.
- Local<Object> buf =
- Buffer::Copy(env, data, cached_data->length).ToLocalChecked();
- return scope.Escape(buf);
+ 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));
} else {
return scope.Escape(fun);
}
}
-void Initialize(Local<Object> target,
- Local<Value> unused,
- Local<Context> context) {
+void NativeModuleLoader::Initialize(Local<Object> target,
+ Local<Value> unused,
+ Local<Context> context) {
Environment* env = Environment::GetCurrent(context);
- target
- ->Set(context,
- FIXED_ONE_BYTE_STRING(env->isolate(), "source"),
- env->native_modules_source())
- .FromJust();
- target
- ->Set(context,
- FIXED_ONE_BYTE_STRING(env->isolate(), "sourceHash"),
- env->native_modules_source_hash())
- .FromJust();
- target
- ->Set(context,
- FIXED_ONE_BYTE_STRING(env->isolate(), "codeCache"),
- env->native_modules_code_cache())
- .FromJust();
- target
- ->Set(context,
- FIXED_ONE_BYTE_STRING(env->isolate(), "codeCacheHash"),
- env->native_modules_code_cache_hash())
- .FromJust();
- target
- ->Set(context,
- FIXED_ONE_BYTE_STRING(env->isolate(), "compiledWithCache"),
- env->native_modules_with_cache())
- .FromJust();
- target
- ->Set(context,
- FIXED_ONE_BYTE_STRING(env->isolate(), "compiledWithoutCache"),
- env->native_modules_without_cache())
- .FromJust();
-
- env->SetMethod(target, "compileFunction", NativeModule::CompileFunction);
- env->SetMethod(target, "compileCodeCache", NativeModule::CompileCodeCache);
+ env->SetMethod(
+ target, "getSource", NativeModuleLoader::GetSourceObject);
+ env->SetMethod(
+ target, "getCacheUsage", NativeModuleLoader::GetCacheUsage);
+ env->SetMethod(
+ target, "compileFunction", NativeModuleLoader::CompileFunction);
+ env->SetMethod(
+ target, "compileCodeCache", NativeModuleLoader::CompileCodeCache);
// internalBinding('native_module') should be frozen
target->SetIntegrityLevel(context, IntegrityLevel::kFrozen).FromJust();
}
@@ -322,5 +322,5 @@ void Initialize(Local<Object> target,
} // namespace native_module
} // namespace node
-NODE_MODULE_CONTEXT_AWARE_INTERNAL(native_module,
- node::native_module::Initialize)
+NODE_MODULE_CONTEXT_AWARE_INTERNAL(
+ native_module, node::native_module::NativeModuleLoader::Initialize)