Index: src/d8.cc |
diff --git a/src/d8.cc b/src/d8.cc |
index 4ab7af6d2c7fedd22e61b098b0d2038285d0f3d2..073290e8e27d10800aba8c8370b0ac479d029aec 100644 |
--- a/src/d8.cc |
+++ b/src/d8.cc |
@@ -440,6 +440,8 @@ ScriptCompiler::CachedData* CompileForCachedData( |
} |
Isolate::CreateParams create_params; |
create_params.array_buffer_allocator = Shell::array_buffer_allocator; |
+ create_params.host_import_module_dynamically_callback_ = |
+ Shell::HostImportModuleDynamically; |
Isolate* temp_isolate = Isolate::New(create_params); |
ScriptCompiler::CachedData* result = NULL; |
{ |
@@ -448,19 +450,21 @@ ScriptCompiler::CachedData* CompileForCachedData( |
Context::Scope context_scope(Context::New(temp_isolate)); |
Local<String> source_copy = |
v8::String::NewFromTwoByte(temp_isolate, source_buffer, |
- v8::NewStringType::kNormal, |
- source_length).ToLocalChecked(); |
+ v8::NewStringType::kNormal, source_length) |
+ .ToLocalChecked(); |
Local<Value> name_copy; |
if (name_buffer) { |
- name_copy = v8::String::NewFromTwoByte(temp_isolate, name_buffer, |
- v8::NewStringType::kNormal, |
- name_length).ToLocalChecked(); |
+ name_copy = |
+ v8::String::NewFromTwoByte(temp_isolate, name_buffer, |
+ v8::NewStringType::kNormal, name_length) |
+ .ToLocalChecked(); |
} else { |
name_copy = v8::Undefined(temp_isolate); |
} |
ScriptCompiler::Source script_source(source_copy, ScriptOrigin(name_copy)); |
if (!ScriptCompiler::CompileUnboundScript(temp_isolate, &script_source, |
- compile_options).IsEmpty() && |
+ compile_options) |
+ .IsEmpty() && |
script_source.GetCachedData()) { |
int length = script_source.GetCachedData()->length; |
uint8_t* cache = new uint8_t[length]; |
@@ -727,6 +731,142 @@ MaybeLocal<Module> Shell::FetchModuleTree(Local<Context> context, |
return module; |
} |
+MaybeLocal<Module> Shell::DynamicFetchModuleTree(Local<Context> context, |
+ Local<Promise> promise, |
+ 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()); |
+ |
+ if (source_text.IsEmpty()) { |
+ // TODO(gsathya): Create an exception |
+ printf("Error reading '%s'\n", file_name.c_str()); |
+ return MaybeLocal<Module>(); |
+ } |
+ |
+ ScriptOrigin origin( |
+ String::NewFromUtf8(isolate, file_name.c_str(), NewStringType::kNormal) |
+ .ToLocalChecked(), |
+ Local<Integer>(), Local<Integer>(), Local<Boolean>(), Local<Integer>(), |
+ Local<Value>(), Local<Boolean>(), Local<Boolean>(), True(isolate)); |
+ |
+ ScriptCompiler::Source source(source_text, origin); |
+ Local<Module> module; |
+ |
+ if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) { |
+ CHECK(Module::FinishDynamicImportFailure(context, promise, |
adamk
2017/03/16 21:41:23
I think you should factor out the exception report
gsathya
2017/03/17 00:47:22
Done.
|
+ try_catch.Exception())); |
+ return MaybeLocal<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); |
+ 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 (!d->specifier_to_module_map.count(absolute_path)) { |
+ if (DynamicFetchModuleTree(context, promise, absolute_path).IsEmpty()) { |
+ return MaybeLocal<Module>(); |
+ } |
+ } |
+ } |
+ |
+ return module; |
+} |
+ |
+namespace { |
+ |
+struct DynamicImportData { |
+ public: |
+ DynamicImportData(Isolate* isolate_, Local<String> referrer_, |
+ Local<String> specifier_, Local<Promise> promise_) |
+ : isolate(isolate_) { |
+ referrer.Reset(isolate, referrer_); |
+ specifier.Reset(isolate, specifier_); |
+ promise.Reset(isolate, promise_); |
+ } |
+ |
+ Isolate* isolate; |
+ Global<String> referrer; |
+ Global<String> specifier; |
+ Global<Promise> promise; |
+}; |
+ |
+} // namespace |
+void Shell::HostImportModuleDynamically(Isolate* isolate, |
+ Local<String> referrer, |
+ Local<String> specifier, |
+ Local<Promise> promise) { |
+ DynamicImportData* data = |
+ new DynamicImportData(isolate, referrer, specifier, promise); |
+ isolate->EnqueueMicrotask(Shell::DoHostImportModuleDynamically, data); |
+} |
+ |
+void Shell::DoHostImportModuleDynamically(void* import_data) { |
+ DynamicImportData* import_data_ = |
adamk
2017/03/16 21:41:23
This should be a std::unique_ptr so it'll get auto
gsathya
2017/03/17 00:47:22
Done.
|
+ static_cast<DynamicImportData*>(import_data); |
+ Isolate* isolate(import_data_->isolate); |
+ HandleScope handle_scope(isolate); |
+ |
+ Local<String> referrer(import_data_->referrer.Get(isolate)); |
+ Local<String> specifier(import_data_->specifier.Get(isolate)); |
+ Local<Promise> promise(import_data_->promise.Get(isolate)); |
+ |
+ PerIsolateData* data = PerIsolateData::Get(isolate); |
+ Local<Context> realm = data->realms_[data->realm_current_].Get(isolate); |
+ Context::Scope context_scope(realm); |
+ |
+ std::string source_url = ToSTLString(referrer); |
+ std::string dir_name = |
+ IsAbsolutePath(source_url) ? DirName(source_url) : GetWorkingDirectory(); |
+ std::string file_name = ToSTLString(specifier); |
+ std::string absolute_path = NormalizePath(file_name.c_str(), dir_name); |
+ |
+ ModuleEmbedderData* d = GetModuleDataFromContext(realm); |
+ Local<Module> root_module; |
+ auto module_it = d->specifier_to_module_map.find(absolute_path); |
+ if (module_it != d->specifier_to_module_map.end()) { |
+ root_module = module_it->second.Get(isolate); |
+ } else if (!DynamicFetchModuleTree(realm, promise, absolute_path) |
+ .ToLocal(&root_module)) { |
+ delete import_data_; |
+ return; |
+ } |
+ |
+ TryCatch try_catch(isolate); |
+ try_catch.SetVerbose(true); |
+ |
+ MaybeLocal<Value> maybe_result; |
+ if (root_module->Instantiate(realm, ResolveModuleCallback)) { |
+ maybe_result = root_module->Evaluate(realm); |
+ EmptyMessageQueues(isolate); |
+ } |
+ |
+ Local<Value> result; |
+ if (!maybe_result.ToLocal(&result)) { |
+ DCHECK(try_catch.HasCaught()); |
+ CHECK(Module::FinishDynamicImportFailure(realm, promise, |
+ try_catch.Exception())); |
+ delete import_data_; |
+ return; |
+ } |
+ |
+ DCHECK(!try_catch.HasCaught()); |
+ CHECK(Module::FinishDynamicImportSuccess(realm, promise, root_module)); |
+ delete import_data_; |
+} |
+ |
bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) { |
HandleScope handle_scope(isolate); |
@@ -2166,6 +2306,8 @@ base::Thread::Options SourceGroup::GetThreadOptions() { |
void SourceGroup::ExecuteInThread() { |
Isolate::CreateParams create_params; |
create_params.array_buffer_allocator = Shell::array_buffer_allocator; |
+ create_params.host_import_module_dynamically_callback_ = |
+ Shell::HostImportModuleDynamically; |
Isolate* isolate = Isolate::New(create_params); |
for (int i = 0; i < Shell::options.stress_runs; ++i) { |
next_semaphore_.Wait(); |
@@ -2304,6 +2446,8 @@ void Worker::WaitForThread() { |
void Worker::ExecuteInThread() { |
Isolate::CreateParams create_params; |
create_params.array_buffer_allocator = Shell::array_buffer_allocator; |
+ create_params.host_import_module_dynamically_callback_ = |
+ Shell::HostImportModuleDynamically; |
Isolate* isolate = Isolate::New(create_params); |
{ |
Isolate::Scope iscope(isolate); |
@@ -2954,6 +3098,9 @@ int Shell::Main(int argc, char* argv[]) { |
create_params.add_histogram_sample_callback = AddHistogramSample; |
} |
+ create_params.host_import_module_dynamically_callback_ = |
+ Shell::HostImportModuleDynamically; |
+ |
if (i::trap_handler::UseTrapHandler()) { |
if (!v8::V8::RegisterDefaultSignalHandler()) { |
fprintf(stderr, "Could not register signal handler"); |