diff options
Diffstat (limited to 'core/libdeno')
-rw-r--r-- | core/libdeno/binding.cc | 6 | ||||
-rw-r--r-- | core/libdeno/deno.h | 4 | ||||
-rw-r--r-- | core/libdeno/modules.cc | 19 | ||||
-rw-r--r-- | core/libdeno/modules_test.cc | 82 |
4 files changed, 104 insertions, 7 deletions
diff --git a/core/libdeno/binding.cc b/core/libdeno/binding.cc index f8ef1c7a7..eac104677 100644 --- a/core/libdeno/binding.cc +++ b/core/libdeno/binding.cc @@ -521,6 +521,8 @@ v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallback( auto* isolate = context->GetIsolate(); DenoIsolate* d = DenoIsolate::FromIsolate(isolate); v8::Isolate::Scope isolate_scope(isolate); + v8::Context::Scope context_scope(context); + v8::EscapableHandleScope handle_scope(isolate); v8::String::Utf8Value specifier_str(isolate, specifier); @@ -544,7 +546,9 @@ v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallback( d->dyn_import_cb_(d->user_data_, *specifier_str, *referrer_name_str, import_id); - return resolver->GetPromise(); + + auto promise = resolver->GetPromise(); + return handle_scope.Escape(promise); } void DenoIsolate::AddIsolate(v8::Isolate* isolate) { diff --git a/core/libdeno/deno.h b/core/libdeno/deno.h index 8525848eb..745285554 100644 --- a/core/libdeno/deno.h +++ b/core/libdeno/deno.h @@ -126,7 +126,9 @@ void deno_mod_instantiate(Deno* d, void* user_data, deno_mod id, void deno_mod_evaluate(Deno* d, void* user_data, deno_mod id); // Call exactly once for every deno_dyn_import_cb. -void deno_dyn_import(Deno* d, deno_dyn_import_id id, deno_mod mod_id); +// Note this call will execute JS. +void deno_dyn_import(Deno* d, void* user_data, deno_dyn_import_id id, + deno_mod mod_id); #ifdef __cplusplus } // extern "C" diff --git a/core/libdeno/modules.cc b/core/libdeno/modules.cc index 3451a3a69..77b330c3e 100644 --- a/core/libdeno/modules.cc +++ b/core/libdeno/modules.cc @@ -151,13 +151,19 @@ void deno_mod_evaluate(Deno* d_, void* user_data, deno_mod id) { } } -void deno_dyn_import(Deno* d_, deno_dyn_import_id import_id, deno_mod mod_id) { +void deno_dyn_import(Deno* d_, void* user_data, deno_dyn_import_id import_id, + deno_mod mod_id) { auto* d = unwrap(d_); + deno::UserDataScope user_data_scope(d, user_data); + auto* isolate = d->isolate_; v8::Isolate::Scope isolate_scope(isolate); v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); auto context = d->context_.Get(d->isolate_); + v8::Context::Scope context_scope(context); + + v8::TryCatch try_catch(isolate); auto it = d->dyn_import_map_.find(import_id); if (it == d->dyn_import_map_.end()) { @@ -168,9 +174,13 @@ void deno_dyn_import(Deno* d_, deno_dyn_import_id import_id, deno_mod mod_id) { /// Resolve. auto persistent_promise = &it->second; auto promise = persistent_promise->Get(isolate); - persistent_promise->Reset(); auto* info = d->GetModuleInfo(mod_id); + + // Do the following callback into JS?? Is user_data_scope needed? + persistent_promise->Reset(); + d->dyn_import_map_.erase(it); + if (info == nullptr) { // Resolution error. promise->Reject(context, v8::Null(isolate)).ToChecked(); @@ -181,7 +191,10 @@ void deno_dyn_import(Deno* d_, deno_dyn_import_id import_id, deno_mod mod_id) { Local<Value> module_namespace = module->GetModuleNamespace(); promise->Resolve(context, module_namespace).ToChecked(); } - d->dyn_import_map_.erase(it); + + if (try_catch.HasCaught()) { + HandleException(context, try_catch.Exception()); + } } } // extern "C" diff --git a/core/libdeno/modules_test.cc b/core/libdeno/modules_test.cc index bb29e7c62..490dccdbe 100644 --- a/core/libdeno/modules_test.cc +++ b/core/libdeno/modules_test.cc @@ -158,7 +158,7 @@ TEST(ModulesTest, DynamicImportSuccess) { dyn_import_count++; EXPECT_STREQ(specifier, "foo"); EXPECT_STREQ(referrer, "a.js"); - deno_dyn_import(d, import_id, b); + deno_dyn_import(d, d, import_id, b); }; const char* src = "(async () => { \n" @@ -198,7 +198,7 @@ TEST(ModulesTest, DynamicImportError) { EXPECT_STREQ(specifier, "foo"); EXPECT_STREQ(referrer, "a.js"); // We indicate there was an error resolving by returning mod_id 0. - deno_dyn_import(d, import_id, 0); + deno_dyn_import(d, d, import_id, 0); }; const char* src = "(async () => { \n" @@ -222,3 +222,81 @@ TEST(ModulesTest, DynamicImportError) { EXPECT_EQ(0, exec_count); EXPECT_EQ(1, dyn_import_count); } + +TEST(ModulesTest, DynamicImportAsync) { + exec_count = 0; + static int dyn_import_count = 0; + static deno_mod b = 0; + static std::vector<deno_dyn_import_id> import_ids = {}; + auto dyn_import_cb = [](auto user_data, const char* specifier, + const char* referrer, deno_dyn_import_id import_id) { + // auto d = reinterpret_cast<Deno*>(user_data); + dyn_import_count++; + EXPECT_STREQ(specifier, "foo"); + EXPECT_STREQ(referrer, "a.js"); + // We don't call deno_dyn_import until later. + import_ids.push_back(import_id); + }; + const char* src = + "(async () => { \n" + " let mod = await import('foo'); \n" + " assert(mod.b() === 'b'); \n" + // AGAIN! + " mod = await import('foo'); \n" + " assert(mod.b() === 'b'); \n" + // Send a message to signify that we're done. + " Deno.core.send(new Uint8Array([4])); \n" + "})(); \n"; + Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, dyn_import_cb}); + static deno_mod a = deno_mod_new(d, true, "a.js", src); + EXPECT_NE(a, 0); + EXPECT_EQ(nullptr, deno_last_exception(d)); + deno_mod_instantiate(d, d, a, nullptr); + EXPECT_EQ(nullptr, deno_last_exception(d)); + + // Evaluate. We check that there are no errors, and Deno.core.send has not + // been called. + deno_mod_evaluate(d, d, a); + EXPECT_EQ(nullptr, deno_last_exception(d)); + deno_check_promise_errors(d); + EXPECT_EQ(deno_last_exception(d), nullptr); + EXPECT_EQ(0, exec_count); + EXPECT_EQ(1, dyn_import_count); + + // Instantiate b.js + const char* b_src = "export function b() { return 'b' }"; + b = deno_mod_new(d, false, "b.js", b_src); + EXPECT_NE(b, 0); + EXPECT_EQ(nullptr, deno_last_exception(d)); + deno_mod_instantiate(d, d, b, nullptr); + EXPECT_EQ(nullptr, deno_last_exception(d)); + + // Now we resolve the import. + EXPECT_EQ(1u, import_ids.size()); + auto import_id = import_ids.back(); + import_ids.pop_back(); + + deno_dyn_import(d, d, import_id, b); + + EXPECT_EQ(nullptr, deno_last_exception(d)); + deno_check_promise_errors(d); + EXPECT_EQ(deno_last_exception(d), nullptr); + + EXPECT_EQ(1u, import_ids.size()); + EXPECT_EQ(2, dyn_import_count); + EXPECT_EQ(0, exec_count); + + import_id = import_ids.back(); + import_ids.pop_back(); + deno_dyn_import(d, d, import_id, b); + + EXPECT_EQ(nullptr, deno_last_exception(d)); + deno_check_promise_errors(d); + EXPECT_EQ(deno_last_exception(d), nullptr); + + // We still have to resolve the second one + EXPECT_EQ(2, dyn_import_count); + EXPECT_EQ(1, exec_count); + + deno_delete(d); +} |