From 7dead8440c7ee28131cf496daa7c286eecfd90c7 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 19 Nov 2019 15:42:09 +0100 Subject: [PATCH] src: add LoadEnvironment() variant taking a string Allow passing a string as the main module rather than using the callback variant. PR-URL: https://github.com/nodejs/node/pull/30467 Reviewed-By: James M Snell Reviewed-By: Gireesh Punathil --- src/api/environment.cc | 36 ++++++++++++++++++++++++++++++++- src/env-inl.h | 5 +++++ src/env.h | 7 +++++++ src/node.h | 4 ++++ src/node_native_module.cc | 8 ++++++++ src/node_native_module.h | 2 ++ src/node_native_module_env.cc | 4 ++++ src/node_native_module_env.h | 1 + src/node_worker.cc | 2 +- test/cctest/test_environment.cc | 27 +++++++++++++++++++++++++ 10 files changed, 94 insertions(+), 2 deletions(-) diff --git a/src/api/environment.cc b/src/api/environment.cc index beec7da66e9845..64b37f929c5212 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc @@ -422,7 +422,9 @@ NODE_EXTERN std::unique_ptr GetInspectorParentHandle( } void LoadEnvironment(Environment* env) { - USE(LoadEnvironment(env, nullptr, {})); + USE(LoadEnvironment(env, + StartExecutionCallback{}, + {})); } MaybeLocal LoadEnvironment( @@ -445,6 +447,38 @@ MaybeLocal LoadEnvironment( return StartExecution(env, cb); } +MaybeLocal LoadEnvironment( + Environment* env, + const char* main_script_source_utf8, + std::unique_ptr inspector_parent_handle) { + CHECK_NOT_NULL(main_script_source_utf8); + return LoadEnvironment( + env, + [&](const StartExecutionCallbackInfo& info) -> MaybeLocal { + // This is a slightly hacky way to convert UTF-8 to UTF-16. + Local str = + String::NewFromUtf8(env->isolate(), + main_script_source_utf8, + v8::NewStringType::kNormal).ToLocalChecked(); + auto main_utf16 = std::make_unique(env->isolate(), str); + + // TODO(addaleax): Avoid having a global table for all scripts. + std::string name = "embedder_main_" + std::to_string(env->thread_id()); + native_module::NativeModuleEnv::Add( + name.c_str(), + UnionBytes(**main_utf16, main_utf16->length())); + env->set_main_utf16(std::move(main_utf16)); + std::vector> params = { + env->process_string(), + env->require_string()}; + std::vector> args = { + env->process_object(), + env->native_module_require()}; + return ExecuteBootstrapper(env, name.c_str(), ¶ms, &args); + }, + std::move(inspector_parent_handle)); +} + Environment* GetCurrentEnvironment(Local context) { return Environment::GetCurrent(context); } diff --git a/src/env-inl.h b/src/env-inl.h index d78ed09d40de7a..5ee9ea6ef02e10 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -1266,6 +1266,11 @@ int64_t Environment::base_object_count() const { return base_object_count_; } +void Environment::set_main_utf16(std::unique_ptr str) { + CHECK(!main_utf16_); + main_utf16_ = std::move(str); +} + #define VP(PropertyName, StringValue) V(v8::Private, PropertyName) #define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName) #define VS(PropertyName, StringValue) V(v8::String, PropertyName) diff --git a/src/env.h b/src/env.h index d7ddd8e1a3f636..9d6c05c12efa02 100644 --- a/src/env.h +++ b/src/env.h @@ -1253,6 +1253,8 @@ class Environment : public MemoryRetainer { #endif // HAVE_INSPECTOR + inline void set_main_utf16(std::unique_ptr); + private: template inline void CreateImmediate(Fn&& cb, bool ref); @@ -1462,6 +1464,11 @@ class Environment : public MemoryRetainer { #undef V v8::Global context_; + + // Keeps the main script source alive is one was passed to LoadEnvironment(). + // We should probably find a way to just use plain `v8::String`s created from + // the source passed to LoadEnvironment() directly instead. + std::unique_ptr main_utf16_; }; } // namespace node diff --git a/src/node.h b/src/node.h index 9561ca39e250ad..b69dd32b4e0480 100644 --- a/src/node.h +++ b/src/node.h @@ -453,6 +453,10 @@ NODE_EXTERN v8::MaybeLocal LoadEnvironment( Environment* env, StartExecutionCallback cb, std::unique_ptr inspector_parent_handle = {}); +NODE_EXTERN v8::MaybeLocal LoadEnvironment( + Environment* env, + const char* main_script_source_utf8, + std::unique_ptr inspector_parent_handle = {}); NODE_EXTERN void FreeEnvironment(Environment* env); // This may return nullptr if context is not associated with a Node instance. diff --git a/src/node_native_module.cc b/src/node_native_module.cc index 1b916d645d8639..c3a77198090f86 100644 --- a/src/node_native_module.cc +++ b/src/node_native_module.cc @@ -33,6 +33,14 @@ bool NativeModuleLoader::Exists(const char* id) { return source_.find(id) != source_.end(); } +bool NativeModuleLoader::Add(const char* id, const UnionBytes& source) { + if (Exists(id)) { + return false; + } + source_.emplace(id, source); + return true; +} + Local NativeModuleLoader::GetSourceObject(Local context) { Isolate* isolate = context->GetIsolate(); Local out = Object::New(isolate); diff --git a/src/node_native_module.h b/src/node_native_module.h index c0bce3bce42c84..3be3f2364dd252 100644 --- a/src/node_native_module.h +++ b/src/node_native_module.h @@ -47,6 +47,8 @@ class NativeModuleLoader { UnionBytes GetConfig(); // Return data for config.gypi bool Exists(const char* id); + bool Add(const char* id, const UnionBytes& source); + v8::Local GetSourceObject(v8::Local context); v8::Local GetConfigString(v8::Isolate* isolate); std::vector GetModuleIds(); diff --git a/src/node_native_module_env.cc b/src/node_native_module_env.cc index 31536000fc8d2f..b48ae962dd639f 100644 --- a/src/node_native_module_env.cc +++ b/src/node_native_module_env.cc @@ -33,6 +33,10 @@ Local ToJsSet(Local context, const std::set& in) { return out; } +bool NativeModuleEnv::Add(const char* id, const UnionBytes& source) { + return NativeModuleLoader::GetInstance()->Add(id, source); +} + bool NativeModuleEnv::Exists(const char* id) { return NativeModuleLoader::GetInstance()->Exists(id); } diff --git a/src/node_native_module_env.h b/src/node_native_module_env.h index f662c67be50d40..bc36be75109639 100644 --- a/src/node_native_module_env.h +++ b/src/node_native_module_env.h @@ -29,6 +29,7 @@ class NativeModuleEnv { // Returns config.gypi as a JSON string static v8::Local GetConfigString(v8::Isolate* isolate); static bool Exists(const char* id); + static bool Add(const char* id, const UnionBytes& source); // Loads data into NativeModuleLoader::.instance.code_cache_ // Generated by mkcodecache as node_code_cache.cc when diff --git a/src/node_worker.cc b/src/node_worker.cc index 6772cb9c91f00f..d359f6fcea2939 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -323,7 +323,7 @@ void Worker::Run() { CreateEnvMessagePort(env_.get()); Debug(this, "Created message port for worker %llu", thread_id_.id); if (LoadEnvironment(env_.get(), - nullptr, + StartExecutionCallback{}, std::move(inspector_parent_handle_)) .IsEmpty()) { return; diff --git a/test/cctest/test_environment.cc b/test/cctest/test_environment.cc index a79c4709a31ef8..15d9b45d490e8f 100644 --- a/test/cctest/test_environment.cc +++ b/test/cctest/test_environment.cc @@ -80,6 +80,33 @@ TEST_F(EnvironmentTest, LoadEnvironmentWithCallback) { CHECK(called_cb); } +TEST_F(EnvironmentTest, LoadEnvironmentWithSource) { + const v8::HandleScope handle_scope(isolate_); + const Argv argv; + Env env {handle_scope, argv}; + + v8::Local context = isolate_->GetCurrentContext(); + v8::Local main_ret = + node::LoadEnvironment(*env, + "return { process, require };").ToLocalChecked(); + + CHECK(main_ret->IsObject()); + CHECK(main_ret.As()->Get( + context, + v8::String::NewFromOneByte( + isolate_, + reinterpret_cast("process"), + v8::NewStringType::kNormal).ToLocalChecked()) + .ToLocalChecked()->IsObject()); + CHECK(main_ret.As()->Get( + context, + v8::String::NewFromOneByte( + isolate_, + reinterpret_cast("require"), + v8::NewStringType::kNormal).ToLocalChecked()) + .ToLocalChecked()->IsFunction()); +} + TEST_F(EnvironmentTest, AtExitWithEnvironment) { const v8::HandleScope handle_scope(isolate_); const Argv argv;