Skip to content

Commit

Permalink
src: add LoadEnvironment() variant taking a string
Browse files Browse the repository at this point in the history
Allow passing a string as the main module rather than using
the callback variant.

PR-URL: #30467
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Gireesh Punathil <[email protected]>
  • Loading branch information
addaleax committed Mar 21, 2020
1 parent c44edec commit 7dead84
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 2 deletions.
36 changes: 35 additions & 1 deletion src/api/environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,9 @@ NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
}

void LoadEnvironment(Environment* env) {
USE(LoadEnvironment(env, nullptr, {}));
USE(LoadEnvironment(env,
StartExecutionCallback{},
{}));
}

MaybeLocal<Value> LoadEnvironment(
Expand All @@ -445,6 +447,38 @@ MaybeLocal<Value> LoadEnvironment(
return StartExecution(env, cb);
}

MaybeLocal<Value> LoadEnvironment(
Environment* env,
const char* main_script_source_utf8,
std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {
CHECK_NOT_NULL(main_script_source_utf8);
return LoadEnvironment(
env,
[&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
// This is a slightly hacky way to convert UTF-8 to UTF-16.
Local<String> str =
String::NewFromUtf8(env->isolate(),
main_script_source_utf8,
v8::NewStringType::kNormal).ToLocalChecked();
auto main_utf16 = std::make_unique<String::Value>(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<Local<String>> params = {
env->process_string(),
env->require_string()};
std::vector<Local<Value>> args = {
env->process_object(),
env->native_module_require()};
return ExecuteBootstrapper(env, name.c_str(), &params, &args);
},
std::move(inspector_parent_handle));
}

Environment* GetCurrentEnvironment(Local<Context> context) {
return Environment::GetCurrent(context);
}
Expand Down
5 changes: 5 additions & 0 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1266,6 +1266,11 @@ int64_t Environment::base_object_count() const {
return base_object_count_;
}

void Environment::set_main_utf16(std::unique_ptr<v8::String::Value> 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)
Expand Down
7 changes: 7 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,8 @@ class Environment : public MemoryRetainer {

#endif // HAVE_INSPECTOR

inline void set_main_utf16(std::unique_ptr<v8::String::Value>);

private:
template <typename Fn>
inline void CreateImmediate(Fn&& cb, bool ref);
Expand Down Expand Up @@ -1462,6 +1464,11 @@ class Environment : public MemoryRetainer {
#undef V

v8::Global<v8::Context> 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<v8::String::Value> main_utf16_;
};

} // namespace node
Expand Down
4 changes: 4 additions & 0 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,10 @@ NODE_EXTERN v8::MaybeLocal<v8::Value> LoadEnvironment(
Environment* env,
StartExecutionCallback cb,
std::unique_ptr<InspectorParentHandle> inspector_parent_handle = {});
NODE_EXTERN v8::MaybeLocal<v8::Value> LoadEnvironment(
Environment* env,
const char* main_script_source_utf8,
std::unique_ptr<InspectorParentHandle> inspector_parent_handle = {});
NODE_EXTERN void FreeEnvironment(Environment* env);

// This may return nullptr if context is not associated with a Node instance.
Expand Down
8 changes: 8 additions & 0 deletions src/node_native_module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<Object> NativeModuleLoader::GetSourceObject(Local<Context> context) {
Isolate* isolate = context->GetIsolate();
Local<Object> out = Object::New(isolate);
Expand Down
2 changes: 2 additions & 0 deletions src/node_native_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<v8::Object> GetSourceObject(v8::Local<v8::Context> context);
v8::Local<v8::String> GetConfigString(v8::Isolate* isolate);
std::vector<std::string> GetModuleIds();
Expand Down
4 changes: 4 additions & 0 deletions src/node_native_module_env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ Local<Set> ToJsSet(Local<Context> context, const std::set<std::string>& 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);
}
Expand Down
1 change: 1 addition & 0 deletions src/node_native_module_env.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class NativeModuleEnv {
// Returns config.gypi as a JSON string
static v8::Local<v8::String> 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
Expand Down
2 changes: 1 addition & 1 deletion src/node_worker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
27 changes: 27 additions & 0 deletions test/cctest/test_environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<v8::Context> context = isolate_->GetCurrentContext();
v8::Local<v8::Value> main_ret =
node::LoadEnvironment(*env,
"return { process, require };").ToLocalChecked();

CHECK(main_ret->IsObject());
CHECK(main_ret.As<v8::Object>()->Get(
context,
v8::String::NewFromOneByte(
isolate_,
reinterpret_cast<const uint8_t*>("process"),
v8::NewStringType::kNormal).ToLocalChecked())
.ToLocalChecked()->IsObject());
CHECK(main_ret.As<v8::Object>()->Get(
context,
v8::String::NewFromOneByte(
isolate_,
reinterpret_cast<const uint8_t*>("require"),
v8::NewStringType::kNormal).ToLocalChecked())
.ToLocalChecked()->IsFunction());
}

TEST_F(EnvironmentTest, AtExitWithEnvironment) {
const v8::HandleScope handle_scope(isolate_);
const Argv argv;
Expand Down

0 comments on commit 7dead84

Please sign in to comment.