// Copyright 2018 the Deno authors. All rights reserved. MIT license. #include "exceptions.h" #include "internal.h" using deno::ClearException; using deno::DenoIsolate; using deno::HandleException; using v8::Boolean; using v8::Context; using v8::EscapableHandleScope; using v8::HandleScope; using v8::Integer; using v8::Isolate; using v8::Local; using v8::Locker; using v8::Module; using v8::Object; using v8::ScriptCompiler; using v8::ScriptOrigin; using v8::String; using v8::Value; v8::MaybeLocal ResolveCallback(Local context, Local specifier, Local referrer) { auto* isolate = context->GetIsolate(); v8::Isolate::Scope isolate_scope(isolate); v8::Locker locker(isolate); DenoIsolate* d = DenoIsolate::FromIsolate(isolate); v8::EscapableHandleScope handle_scope(isolate); deno_mod referrer_id = referrer->GetIdentityHash(); auto* referrer_info = d->GetModuleInfo(referrer_id); CHECK_NOT_NULL(referrer_info); for (int i = 0; i < referrer->GetModuleRequestsLength(); i++) { Local req = referrer->GetModuleRequest(i); if (req->Equals(context, specifier).ToChecked()) { v8::String::Utf8Value req_utf8(isolate, req); std::string req_str(*req_utf8); deno_mod id = d->resolve_cb_(d->user_data_, req_str.c_str(), referrer_id); // Note: id might be zero, in which case GetModuleInfo will return // nullptr. auto* info = d->GetModuleInfo(id); if (info == nullptr) { char buf[64 * 1024]; snprintf(buf, sizeof(buf), "Cannot resolve module \"%s\" from \"%s\"", req_str.c_str(), referrer_info->name.c_str()); isolate->ThrowException(deno::v8_str(buf)); break; } else { Local child_mod = info->handle.Get(isolate); return handle_scope.Escape(child_mod); } } } return v8::MaybeLocal(); // Error } extern "C" { deno_mod deno_mod_new(Deno* d_, bool main, const char* name_cstr, const char* source_cstr) { auto* d = unwrap(d_); return d->RegisterModule(main, name_cstr, source_cstr); } const char* deno_mod_name(Deno* d_, deno_mod id) { auto* d = unwrap(d_); auto* info = d->GetModuleInfo(id); return info->name.c_str(); } size_t deno_mod_imports_len(Deno* d_, deno_mod id) { auto* d = unwrap(d_); auto* info = d->GetModuleInfo(id); return info->import_specifiers.size(); } const char* deno_mod_imports_get(Deno* d_, deno_mod id, size_t index) { auto* d = unwrap(d_); auto* info = d->GetModuleInfo(id); if (info == nullptr || index >= info->import_specifiers.size()) { return nullptr; } else { return info->import_specifiers[index].c_str(); } } void deno_mod_instantiate(Deno* d_, void* user_data, deno_mod id, deno_resolve_cb cb) { 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); { CHECK_NULL(d->resolve_cb_); d->resolve_cb_ = cb; { auto* info = d->GetModuleInfo(id); if (info == nullptr) { return; } Local module = info->handle.Get(isolate); if (module->GetStatus() == Module::kErrored) { return; } auto maybe_ok = module->InstantiateModule(context, ResolveCallback); CHECK(maybe_ok.IsJust() || try_catch.HasCaught()); } d->resolve_cb_ = nullptr; } if (try_catch.HasCaught()) { HandleException(context, try_catch.Exception()); } } void deno_mod_evaluate(Deno* d_, void* user_data, deno_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); auto* info = d->GetModuleInfo(id); auto module = info->handle.Get(isolate); auto status = module->GetStatus(); if (status == Module::kInstantiated) { bool ok = !module->Evaluate(context).IsEmpty(); status = module->GetStatus(); // Update status after evaluating. if (ok) { // Note status can still be kErrored even if we get ok. CHECK(status == Module::kEvaluated || status == Module::kErrored); } else { CHECK_EQ(status, Module::kErrored); } } switch (status) { case Module::kEvaluated: ClearException(context); break; case Module::kErrored: HandleException(context, module->GetException()); break; default: FATAL("Unexpected module status: %d", static_cast(status)); } } void deno_dyn_import_done(Deno* d_, void* user_data, deno_dyn_import_id import_id, deno_mod mod_id, const char* error_str) { auto* d = unwrap(d_); CHECK((mod_id == 0 && error_str != nullptr) || (mod_id != 0 && error_str == nullptr) || (mod_id == 0 && !d->last_exception_handle_.IsEmpty())); 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); auto it = d->dyn_import_map_.find(import_id); if (it == d->dyn_import_map_.end()) { CHECK(false); // TODO(ry) error on bad import_id. return; } /// Resolve. auto persistent_promise = &it->second; auto promise = persistent_promise->Get(isolate); 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. if (error_str != nullptr) { auto msg = deno::v8_str(error_str); auto exception = v8::Exception::TypeError(msg); promise->Reject(context, exception).ToChecked(); } else { auto e = d->last_exception_handle_.Get(isolate); ClearException(context); promise->Reject(context, e).ToChecked(); } } else { // Resolution success Local module = info->handle.Get(isolate); CHECK_EQ(module->GetStatus(), v8::Module::kEvaluated); Local module_namespace = module->GetModuleNamespace(); promise->Resolve(context, module_namespace).ToChecked(); } d->isolate_->RunMicrotasks(); } } // extern "C"