summaryrefslogtreecommitdiff
path: root/core/libdeno
diff options
context:
space:
mode:
Diffstat (limited to 'core/libdeno')
-rw-r--r--core/libdeno/binding.cc6
-rw-r--r--core/libdeno/deno.h4
-rw-r--r--core/libdeno/modules.cc19
-rw-r--r--core/libdeno/modules_test.cc82
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);
+}