Index: src/d8.cc |
diff --git a/src/d8.cc b/src/d8.cc |
index 920a6f488f203a9a871fd0db0b364677187dbace..938448936dd23aab906a29f44aac8f26c88536a2 100644 |
--- a/src/d8.cc |
+++ b/src/d8.cc |
@@ -9,7 +9,7 @@ |
#include <algorithm> |
#include <fstream> |
-#include <map> |
+#include <unordered_map> |
#include <utility> |
#include <vector> |
@@ -572,29 +572,74 @@ std::string NormalizePath(const std::string& path, |
return result; |
} |
+// Per-context Module data, allowing sharing of module maps |
+// across top-level module loads. |
+class ModuleEmbedderData { |
+ private: |
+ class ModuleGlobalHash { |
+ public: |
+ explicit ModuleGlobalHash(Isolate* isolate) : isolate_(isolate) {} |
+ size_t operator()(const Global<Module>& module) const { |
+ return module.Get(isolate_)->GetIdentityHash(); |
+ } |
+ |
+ private: |
+ Isolate* isolate_; |
+ }; |
+ |
+ public: |
+ explicit ModuleEmbedderData(Isolate* isolate) |
+ : module_to_directory_map(10, ModuleGlobalHash(isolate)) {} |
+ |
+ // Map from normalized module specifier to Module. |
+ std::unordered_map<std::string, Global<Module>> specifier_to_module_map; |
+ // Map from Module to the directory that Module was loaded from. |
+ std::unordered_map<Global<Module>, std::string, ModuleGlobalHash> |
+ module_to_directory_map; |
+}; |
+ |
+enum { |
+ // The debugger reserves the first slot in the Context embedder data. |
+ kDebugIdIndex = Context::kDebugIdIndex, |
+ kModuleEmbedderDataIndex |
+}; |
+ |
+void InitializeModuleEmbedderData(Local<Context> context) { |
+ context->SetAlignedPointerInEmbedderData( |
+ kModuleEmbedderDataIndex, new ModuleEmbedderData(context->GetIsolate())); |
+} |
+ |
+ModuleEmbedderData* GetModuleDataFromContext(Local<Context> context) { |
+ return static_cast<ModuleEmbedderData*>( |
+ context->GetAlignedPointerFromEmbedderData(kModuleEmbedderDataIndex)); |
+} |
+ |
+void DisposeModuleEmbedderData(Local<Context> context) { |
+ delete GetModuleDataFromContext(context); |
+ context->SetAlignedPointerInEmbedderData(kModuleEmbedderDataIndex, nullptr); |
+} |
+ |
MaybeLocal<Module> ResolveModuleCallback(Local<Context> context, |
Local<String> specifier, |
- Local<Module> referrer, |
- Local<Value> data) { |
+ Local<Module> referrer) { |
Isolate* isolate = context->GetIsolate(); |
- auto module_map = static_cast<std::map<std::string, Global<Module>>*>( |
- External::Cast(*data)->Value()); |
- Local<String> dir_name = Local<String>::Cast(referrer->GetEmbedderData()); |
+ ModuleEmbedderData* d = GetModuleDataFromContext(context); |
+ auto dir_name_it = |
+ d->module_to_directory_map.find(Global<Module>(isolate, referrer)); |
+ CHECK(dir_name_it != d->module_to_directory_map.end()); |
std::string absolute_path = |
- NormalizePath(ToSTLString(specifier), ToSTLString(dir_name)); |
- auto it = module_map->find(absolute_path); |
- if (it != module_map->end()) { |
- return it->second.Get(isolate); |
- } |
- return MaybeLocal<Module>(); |
+ NormalizePath(ToSTLString(specifier), dir_name_it->second); |
+ auto module_it = d->specifier_to_module_map.find(absolute_path); |
+ CHECK(module_it != d->specifier_to_module_map.end()); |
+ return module_it->second.Get(isolate); |
} |
} // anonymous namespace |
-MaybeLocal<Module> Shell::FetchModuleTree( |
- Isolate* isolate, const std::string& file_name, |
- std::map<std::string, Global<Module>>* module_map) { |
+MaybeLocal<Module> Shell::FetchModuleTree(Local<Context> context, |
+ const std::string& file_name) { |
DCHECK(IsAbsolutePath(file_name)); |
+ Isolate* isolate = context->GetIsolate(); |
TryCatch try_catch(isolate); |
try_catch.SetVerbose(true); |
Local<String> source_text = ReadFile(isolate, file_name.c_str()); |
@@ -611,19 +656,22 @@ MaybeLocal<Module> Shell::FetchModuleTree( |
ReportException(isolate, &try_catch); |
return MaybeLocal<Module>(); |
} |
- module_map->insert( |
- std::make_pair(file_name, Global<Module>(isolate, module))); |
+ |
+ ModuleEmbedderData* d = GetModuleDataFromContext(context); |
+ CHECK(d->specifier_to_module_map |
+ .insert(std::make_pair(file_name, Global<Module>(isolate, module))) |
+ .second); |
std::string dir_name = DirName(file_name); |
- module->SetEmbedderData( |
- String::NewFromUtf8(isolate, dir_name.c_str(), NewStringType::kNormal) |
- .ToLocalChecked()); |
+ CHECK(d->module_to_directory_map |
+ .insert(std::make_pair(Global<Module>(isolate, module), dir_name)) |
+ .second); |
for (int i = 0, length = module->GetModuleRequestsLength(); i < length; ++i) { |
Local<String> name = module->GetModuleRequest(i); |
std::string absolute_path = NormalizePath(ToSTLString(name), dir_name); |
- if (!module_map->count(absolute_path)) { |
- if (FetchModuleTree(isolate, absolute_path, module_map).IsEmpty()) { |
+ if (!d->specifier_to_module_map.count(absolute_path)) { |
+ if (FetchModuleTree(context, absolute_path).IsEmpty()) { |
return MaybeLocal<Module>(); |
} |
} |
@@ -635,12 +683,14 @@ MaybeLocal<Module> Shell::FetchModuleTree( |
bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) { |
HandleScope handle_scope(isolate); |
+ PerIsolateData* data = PerIsolateData::Get(isolate); |
+ Local<Context> realm = data->realms_[data->realm_current_].Get(isolate); |
+ Context::Scope context_scope(realm); |
+ |
std::string absolute_path = NormalizePath(file_name, GetWorkingDirectory()); |
Local<Module> root_module; |
- std::map<std::string, Global<Module>> module_map; |
- if (!FetchModuleTree(isolate, absolute_path, &module_map) |
- .ToLocal(&root_module)) { |
+ if (!FetchModuleTree(realm, absolute_path).ToLocal(&root_module)) { |
return false; |
} |
@@ -648,16 +698,9 @@ bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) { |
try_catch.SetVerbose(true); |
MaybeLocal<Value> maybe_result; |
- { |
- PerIsolateData* data = PerIsolateData::Get(isolate); |
- Local<Context> realm = data->realms_[data->realm_current_].Get(isolate); |
- Context::Scope context_scope(realm); |
- |
- if (root_module->Instantiate(realm, ResolveModuleCallback, |
- External::New(isolate, &module_map))) { |
- maybe_result = root_module->Evaluate(realm); |
- EmptyMessageQueues(isolate); |
- } |
+ if (root_module->Instantiate(realm, ResolveModuleCallback)) { |
+ maybe_result = root_module->Evaluate(realm); |
+ EmptyMessageQueues(isolate); |
} |
Local<Value> result; |
if (!maybe_result.ToLocal(&result)) { |
@@ -682,9 +725,15 @@ PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) { |
PerIsolateData::RealmScope::~RealmScope() { |
// Drop realms to avoid keeping them alive. |
- for (int i = 0; i < data_->realm_count_; ++i) |
- data_->realms_[i].Reset(); |
+ for (int i = 0; i < data_->realm_count_; ++i) { |
+ Global<Context>& realm = data_->realms_[i]; |
+ if (realm.IsEmpty()) continue; |
+ DisposeModuleEmbedderData(realm.Get(data_->isolate_)); |
+ // TODO(adamk): No need to reset manually, Globals reset when destructed. |
+ realm.Reset(); |
+ } |
delete[] data_->realms_; |
+ // TODO(adamk): No need to reset manually, Globals reset when destructed. |
if (!data_->realm_shared_.IsEmpty()) |
data_->realm_shared_.Reset(); |
} |
@@ -787,6 +836,7 @@ MaybeLocal<Context> Shell::CreateRealm( |
try_catch.ReThrow(); |
return MaybeLocal<Context>(); |
} |
+ InitializeModuleEmbedderData(context); |
data->realms_[index].Reset(isolate, context); |
args.GetReturnValue().Set(index); |
return context; |
@@ -820,6 +870,7 @@ void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) { |
Throw(args.GetIsolate(), "Invalid realm index"); |
return; |
} |
+ DisposeModuleEmbedderData(data->realms_[index].Get(isolate)); |
data->realms_[index].Reset(); |
isolate->ContextDisposedNotification(); |
isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime()); |
@@ -1488,6 +1539,7 @@ Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) { |
EscapableHandleScope handle_scope(isolate); |
Local<Context> context = Context::New(isolate, NULL, global_template); |
DCHECK(!context.IsEmpty()); |
+ InitializeModuleEmbedderData(context); |
Context::Scope scope(context); |
i::Factory* factory = reinterpret_cast<i::Isolate*>(isolate)->factory(); |
@@ -1813,6 +1865,7 @@ void SourceGroup::ExecuteInThread() { |
PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate)); |
Execute(isolate); |
} |
+ DisposeModuleEmbedderData(context); |
} |
Shell::CollectGarbage(isolate); |
} |
@@ -2072,6 +2125,7 @@ void Worker::ExecuteInThread() { |
} |
} |
} |
+ DisposeModuleEmbedderData(context); |
} |
Shell::CollectGarbage(isolate); |
} |
@@ -2255,6 +2309,7 @@ int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) { |
PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate)); |
options.isolate_sources[0].Execute(isolate); |
} |
+ DisposeModuleEmbedderData(context); |
} |
CollectGarbage(isolate); |
for (int i = 1; i < options.num_isolates; ++i) { |