use super::bindings;
use crate::error::exception_to_err_result;
use crate::error::generic_error;
use crate::error::to_v8_type_error;
use crate::module_specifier::ModuleSpecifier;
use crate::modules::ModuleCode;
use crate::modules::ModuleError;
use crate::modules::ModuleId;
use crate::modules::ModuleLoadId;
use crate::modules::ModuleMap;
use crate::ops::OpCtx;
use crate::ops::PendingOp;
use crate::runtime::JsRuntimeState;
use crate::JsRuntime;
use anyhow::Error;
use deno_unsync::JoinSet;
use futures::channel::oneshot;
use futures::stream::StreamExt;
use std::cell::RefCell;
use std::collections::HashSet;
use std::collections::VecDeque;
use std::hash::BuildHasherDefault;
use std::hash::Hasher;
use std::option::Option;
use std::rc::Rc;
use std::task::Context;
use std::task::Poll;
use v8::HandleScope;
use v8::Local;
#[derive(Default)]
pub(crate) struct IdentityHasher(u64);
impl Hasher for IdentityHasher {
fn write_i32(&mut self, i: i32) {
self.0 = i as u64;
}
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, _bytes: &[u8]) {
unreachable!()
}
}
struct DynImportModEvaluate {
load_id: ModuleLoadId,
module_id: ModuleId,
promise: v8::Global<v8::Promise>,
module: v8::Global<v8::Module>,
}
pub(crate) struct ModEvaluate {
promise: Option<v8::Global<v8::Promise>>,
pub(crate) has_evaluated: bool,
pub(crate) handled_promise_rejections: Vec<v8::Global<v8::Promise>>,
sender: oneshot::Sender<Result<(), Error>>,
}
#[derive(Default)]
pub(crate) struct ContextState {
pub(crate) js_event_loop_tick_cb: Option<Rc<v8::Global<v8::Function>>>,
pub(crate) js_build_custom_error_cb: Option<Rc<v8::Global<v8::Function>>>,
pub(crate) js_promise_reject_cb: Option<Rc<v8::Global<v8::Function>>>,
pub(crate) js_format_exception_cb: Option<Rc<v8::Global<v8::Function>>>,
pub(crate) js_wasm_streaming_cb: Option<Rc<v8::Global<v8::Function>>>,
pub(crate) pending_promise_rejections:
VecDeque<(v8::Global<v8::Promise>, v8::Global<v8::Value>)>,
pending_dyn_mod_evaluate: Vec<DynImportModEvaluate>,
pub(crate) pending_mod_evaluate: Option<ModEvaluate>,
pub(crate) unrefed_ops: HashSet<i32, BuildHasherDefault<IdentityHasher>>,
pub(crate) pending_ops: JoinSet<PendingOp>,
pub(crate) op_ctxs: Box<[OpCtx]>,
pub(crate) isolate: Option<*mut v8::OwnedIsolate>,
}
#[derive(Clone)]
#[repr(transparent)]
pub struct JsRealm(pub(crate) JsRealmInner);
#[derive(Clone)]
pub(crate) struct JsRealmInner {
context_state: Rc<RefCell<ContextState>>,
context: Rc<v8::Global<v8::Context>>,
module_map: Rc<RefCell<ModuleMap>>,
runtime_state: Rc<RefCell<JsRuntimeState>>,
is_main_realm: bool,
}
impl JsRealmInner {
pub(crate) fn new(
context_state: Rc<RefCell<ContextState>>,
context: v8::Global<v8::Context>,
module_map: Rc<RefCell<ModuleMap>>,
runtime_state: Rc<RefCell<JsRuntimeState>>,
is_main_realm: bool,
) -> Self {
Self {
context_state,
context: context.into(),
module_map,
runtime_state,
is_main_realm,
}
}
pub fn num_pending_ops(&self) -> usize {
self.context_state.borrow().pending_ops.len()
}
pub fn num_unrefed_ops(&self) -> usize {
self.context_state.borrow().unrefed_ops.len()
}
pub fn has_pending_dyn_imports(&self) -> bool {
self.module_map.borrow().has_pending_dynamic_imports()
}
pub fn has_pending_dyn_module_evaluation(&self) -> bool {
!self
.context_state
.borrow()
.pending_dyn_mod_evaluate
.is_empty()
}
pub fn has_pending_module_evaluation(&self) -> bool {
self.context_state.borrow().pending_mod_evaluate.is_some()
}
#[inline(always)]
pub fn context(&self) -> &v8::Global<v8::Context> {
&self.context
}
#[inline(always)]
pub(crate) fn state(&self) -> Rc<RefCell<ContextState>> {
self.context_state.clone()
}
#[inline(always)]
pub(crate) fn module_map(&self) -> Rc<RefCell<ModuleMap>> {
self.module_map.clone()
}
#[inline(always)]
pub fn handle_scope<'s>(
&self,
isolate: &'s mut v8::Isolate,
) -> v8::HandleScope<'s> {
v8::HandleScope::with_context(isolate, &*self.context)
}
pub(crate) fn check_promise_rejections(
&self,
isolate: &mut v8::Isolate,
) -> Result<(), Error> {
let Some((_, handle)) = self.context_state.borrow_mut().pending_promise_rejections.pop_front() else {
return Ok(());
};
let scope = &mut self.handle_scope(isolate);
let exception = v8::Local::new(scope, handle);
let state_rc = JsRuntime::state_from(scope);
let state = state_rc.borrow();
if let Some(inspector) = &state.inspector {
let inspector = inspector.borrow();
inspector.exception_thrown(scope, exception, true);
if inspector.has_blocking_sessions() {
return Ok(());
}
}
exception_to_err_result(scope, exception, true)
}
pub(crate) fn is_same(&self, other: &Rc<v8::Global<v8::Context>>) -> bool {
Rc::ptr_eq(&self.context, other)
}
pub fn destroy(self) {
let state = self.state();
let raw_ptr = self.state().borrow().isolate.unwrap();
let isolate = unsafe { raw_ptr.as_mut().unwrap() };
let mut realm_state = state.borrow_mut();
std::mem::take(&mut realm_state.js_event_loop_tick_cb);
std::mem::take(&mut realm_state.js_build_custom_error_cb);
std::mem::take(&mut realm_state.js_promise_reject_cb);
std::mem::take(&mut realm_state.js_format_exception_cb);
std::mem::take(&mut realm_state.js_wasm_streaming_cb);
std::mem::take(&mut realm_state.op_ctxs);
self.context().open(isolate).clear_all_slots(isolate);
}
}
impl JsRealm {
pub(crate) fn new(inner: JsRealmInner) -> Self {
Self(inner)
}
#[inline(always)]
pub(crate) fn state_from_scope(
scope: &mut v8::HandleScope,
) -> Rc<RefCell<ContextState>> {
let context = scope.get_current_context();
context
.get_slot::<Rc<RefCell<ContextState>>>(scope)
.unwrap()
.clone()
}
#[inline(always)]
pub(crate) fn module_map_from(
scope: &mut v8::HandleScope,
) -> Rc<RefCell<ModuleMap>> {
let context = scope.get_current_context();
context
.get_slot::<Rc<RefCell<ModuleMap>>>(scope)
.unwrap()
.clone()
}
#[inline(always)]
pub fn num_pending_ops(&self) -> usize {
self.0.num_pending_ops()
}
#[inline(always)]
pub fn num_unrefed_ops(&self) -> usize {
self.0.num_unrefed_ops()
}
#[inline(always)]
pub fn handle_scope<'s>(
&self,
isolate: &'s mut v8::Isolate,
) -> v8::HandleScope<'s> {
self.0.handle_scope(isolate)
}
#[inline(always)]
pub fn context(&self) -> &v8::Global<v8::Context> {
self.0.context()
}
pub fn global_object<'s>(
&self,
isolate: &'s mut v8::Isolate,
) -> v8::Local<'s, v8::Object> {
let scope = &mut self.0.handle_scope(isolate);
self.0.context.open(scope).global(scope)
}
fn string_from_code<'a>(
scope: &mut HandleScope<'a>,
code: &ModuleCode,
) -> Option<Local<'a, v8::String>> {
if let Some(code) = code.try_static_ascii() {
v8::String::new_external_onebyte_static(scope, code)
} else {
v8::String::new_from_utf8(
scope,
code.as_bytes(),
v8::NewStringType::Normal,
)
}
}
pub fn execute_script_static(
&self,
isolate: &mut v8::Isolate,
name: &'static str,
source_code: &'static str,
) -> Result<v8::Global<v8::Value>, Error> {
self.execute_script(isolate, name, ModuleCode::from_static(source_code))
}
pub fn execute_script(
&self,
isolate: &mut v8::Isolate,
name: &'static str,
source_code: ModuleCode,
) -> Result<v8::Global<v8::Value>, Error> {
let scope = &mut self.0.handle_scope(isolate);
let source = Self::string_from_code(scope, &source_code).unwrap();
debug_assert!(name.is_ascii());
let name =
v8::String::new_external_onebyte_static(scope, name.as_bytes()).unwrap();
let origin = bindings::script_origin(scope, name);
let tc_scope = &mut v8::TryCatch::new(scope);
let script = match v8::Script::compile(tc_scope, source, Some(&origin)) {
Some(script) => script,
None => {
let exception = tc_scope.exception().unwrap();
return exception_to_err_result(tc_scope, exception, false);
}
};
match script.run(tc_scope) {
Some(value) => {
let value_handle = v8::Global::new(tc_scope, value);
Ok(value_handle)
}
None => {
assert!(tc_scope.has_caught());
let exception = tc_scope.exception().unwrap();
exception_to_err_result(tc_scope, exception, false)
}
}
}
pub fn get_module_namespace(
&self,
isolate: &mut v8::Isolate,
module_id: ModuleId,
) -> Result<v8::Global<v8::Object>, Error> {
self
.0
.module_map()
.borrow()
.get_module_namespace(&mut self.handle_scope(isolate), module_id)
}
pub(crate) fn instantiate_module(
&self,
isolate: &mut v8::Isolate,
id: ModuleId,
) -> Result<(), v8::Global<v8::Value>> {
self
.0
.module_map()
.borrow_mut()
.instantiate_module(&mut self.handle_scope(isolate), id)
}
fn dynamic_import_module_evaluate(
&self,
isolate: &mut v8::Isolate,
load_id: ModuleLoadId,
id: ModuleId,
) -> Result<(), Error> {
let module_handle = self
.0
.module_map()
.borrow()
.get_handle(id)
.expect("ModuleInfo not found");
let status = {
let scope = &mut self.handle_scope(isolate);
let module = module_handle.open(scope);
module.get_status()
};
match status {
v8::ModuleStatus::Instantiated | v8::ModuleStatus::Evaluated => {}
_ => return Ok(()),
}
let scope = &mut self.handle_scope(isolate);
let tc_scope = &mut v8::TryCatch::new(scope);
let module = v8::Local::new(tc_scope, &module_handle);
let maybe_value = module.evaluate(tc_scope);
let status = module.get_status();
if let Some(value) = maybe_value {
assert!(
status == v8::ModuleStatus::Evaluated
|| status == v8::ModuleStatus::Errored
);
let promise = v8::Local::<v8::Promise>::try_from(value)
.expect("Expected to get promise as module evaluation result");
let empty_fn = bindings::create_empty_fn(tc_scope).unwrap();
promise.catch(tc_scope, empty_fn);
let promise_global = v8::Global::new(tc_scope, promise);
let module_global = v8::Global::new(tc_scope, module);
let dyn_import_mod_evaluate = DynImportModEvaluate {
load_id,
module_id: id,
promise: promise_global,
module: module_global,
};
self
.0
.context_state
.borrow_mut()
.pending_dyn_mod_evaluate
.push(dyn_import_mod_evaluate);
} else if tc_scope.has_terminated() || tc_scope.is_execution_terminating() {
return Err(
generic_error("Cannot evaluate dynamically imported module, because JavaScript execution has been terminated.")
);
} else {
assert!(status == v8::ModuleStatus::Errored);
}
Ok(())
}
pub fn mod_evaluate(
&self,
isolate: &mut v8::Isolate,
id: ModuleId,
) -> oneshot::Receiver<Result<(), Error>> {
let state_rc = self.0.state();
let module_map_rc = self.0.module_map();
let scope = &mut self.handle_scope(isolate);
let tc_scope = &mut v8::TryCatch::new(scope);
let module = module_map_rc
.borrow()
.get_handle(id)
.map(|handle| v8::Local::new(tc_scope, handle))
.expect("ModuleInfo not found");
let mut status = module.get_status();
assert_eq!(
status,
v8::ModuleStatus::Instantiated,
"{} {} ({})",
if status == v8::ModuleStatus::Evaluated {
"Module already evaluated. Perhaps you've re-provided a module or extension that was already included in the snapshot?"
} else {
"Module not instantiated"
},
module_map_rc
.borrow()
.get_info_by_id(id)
.unwrap()
.name
.as_str(),
id,
);
let (sender, receiver) = oneshot::channel();
{
let mut state = state_rc.borrow_mut();
assert!(
state.pending_mod_evaluate.is_none(),
"There is already pending top level module evaluation"
);
state.pending_mod_evaluate = Some(ModEvaluate {
promise: None,
has_evaluated: false,
handled_promise_rejections: vec![],
sender,
});
}
let maybe_value = module.evaluate(tc_scope);
{
let mut state = state_rc.borrow_mut();
let pending_mod_evaluate = state.pending_mod_evaluate.as_mut().unwrap();
pending_mod_evaluate.has_evaluated = true;
}
status = module.get_status();
let has_dispatched_exception = self
.0
.runtime_state
.borrow_mut()
.dispatched_exception
.is_some();
if has_dispatched_exception {
let exception = v8::undefined(tc_scope).into();
let pending_mod_evaluate = {
let mut state = state_rc.borrow_mut();
state.pending_mod_evaluate.take().unwrap()
};
pending_mod_evaluate
.sender
.send(exception_to_err_result(tc_scope, exception, false))
.expect("Failed to send module evaluation error.");
} else if let Some(value) = maybe_value {
assert!(
status == v8::ModuleStatus::Evaluated
|| status == v8::ModuleStatus::Errored
);
let promise = v8::Local::<v8::Promise>::try_from(value)
.expect("Expected to get promise as module evaluation result");
let promise_global = v8::Global::new(tc_scope, promise);
let mut state = state_rc.borrow_mut();
{
let pending_mod_evaluate = state.pending_mod_evaluate.as_ref().unwrap();
let pending_rejection_was_already_handled = pending_mod_evaluate
.handled_promise_rejections
.contains(&promise_global);
if !pending_rejection_was_already_handled {
state
.pending_promise_rejections
.retain(|(key, _)| key != &promise_global);
}
}
let promise_global = v8::Global::new(tc_scope, promise);
state.pending_mod_evaluate.as_mut().unwrap().promise =
Some(promise_global);
tc_scope.perform_microtask_checkpoint();
} else if tc_scope.has_terminated() || tc_scope.is_execution_terminating() {
let pending_mod_evaluate = {
let mut state = state_rc.borrow_mut();
state.pending_mod_evaluate.take().unwrap()
};
pending_mod_evaluate.sender.send(Err(
generic_error("Cannot evaluate module, because JavaScript execution has been terminated.")
)).expect("Failed to send module evaluation error.");
} else {
assert!(status == v8::ModuleStatus::Errored);
}
receiver
}
fn dynamic_import_reject(
&self,
isolate: &mut v8::Isolate,
id: ModuleLoadId,
exception: v8::Global<v8::Value>,
) {
let module_map_rc = self.0.module_map();
let scope = &mut self.handle_scope(isolate);
let resolver_handle = module_map_rc
.borrow_mut()
.dynamic_import_map
.remove(&id)
.expect("Invalid dynamic import id");
let resolver = resolver_handle.open(scope);
let exception = v8::Local::new(scope, exception);
resolver.reject(scope, exception).unwrap();
scope.perform_microtask_checkpoint();
}
fn dynamic_import_resolve(
&self,
isolate: &mut v8::Isolate,
id: ModuleLoadId,
mod_id: ModuleId,
) {
let state_rc = self.0.runtime_state.clone();
let module_map_rc = self.0.module_map();
let scope = &mut self.handle_scope(isolate);
let resolver_handle = module_map_rc
.borrow_mut()
.dynamic_import_map
.remove(&id)
.expect("Invalid dynamic import id");
let resolver = resolver_handle.open(scope);
let module = {
module_map_rc
.borrow()
.get_handle(mod_id)
.map(|handle| v8::Local::new(scope, handle))
.expect("Dyn import module info not found")
};
assert_eq!(module.get_status(), v8::ModuleStatus::Evaluated);
let module_namespace = module.get_module_namespace();
resolver.resolve(scope, module_namespace).unwrap();
state_rc.borrow_mut().dyn_module_evaluate_idle_counter = 0;
scope.perform_microtask_checkpoint();
}
pub(in crate::runtime) fn prepare_dyn_imports(
&self,
isolate: &mut v8::Isolate,
cx: &mut Context,
) -> Poll<Result<(), Error>> {
if self
.0
.module_map()
.borrow()
.preparing_dynamic_imports
.is_empty()
{
return Poll::Ready(Ok(()));
}
loop {
let poll_result = self
.0
.module_map()
.borrow_mut()
.preparing_dynamic_imports
.poll_next_unpin(cx);
if let Poll::Ready(Some(prepare_poll)) = poll_result {
let dyn_import_id = prepare_poll.0;
let prepare_result = prepare_poll.1;
match prepare_result {
Ok(load) => {
self
.0
.module_map()
.borrow_mut()
.pending_dynamic_imports
.push(load.into_future());
}
Err(err) => {
let exception =
to_v8_type_error(&mut self.handle_scope(isolate), err);
self.dynamic_import_reject(isolate, dyn_import_id, exception);
}
}
continue;
}
return Poll::Ready(Ok(()));
}
}
pub(in crate::runtime) fn poll_dyn_imports(
&self,
isolate: &mut v8::Isolate,
cx: &mut Context,
) -> Poll<Result<(), Error>> {
if self
.0
.module_map()
.borrow()
.pending_dynamic_imports
.is_empty()
{
return Poll::Ready(Ok(()));
}
loop {
let poll_result = self
.0
.module_map()
.borrow_mut()
.pending_dynamic_imports
.poll_next_unpin(cx);
if let Poll::Ready(Some(load_stream_poll)) = poll_result {
let maybe_result = load_stream_poll.0;
let mut load = load_stream_poll.1;
let dyn_import_id = load.id;
if let Some(load_stream_result) = maybe_result {
match load_stream_result {
Ok((request, info)) => {
let register_result = load.register_and_recurse(
&mut self.handle_scope(isolate),
&request,
info,
);
match register_result {
Ok(()) => {
self
.0
.module_map()
.borrow_mut()
.pending_dynamic_imports
.push(load.into_future());
}
Err(err) => {
let exception = match err {
ModuleError::Exception(e) => e,
ModuleError::Other(e) => {
to_v8_type_error(&mut self.handle_scope(isolate), e)
}
};
self.dynamic_import_reject(isolate, dyn_import_id, exception)
}
}
}
Err(err) => {
let exception =
to_v8_type_error(&mut self.handle_scope(isolate), err);
self.dynamic_import_reject(isolate, dyn_import_id, exception);
}
}
} else {
let module_id =
load.root_module_id.expect("Root module should be loaded");
let result = self.instantiate_module(isolate, module_id);
if let Err(exception) = result {
self.dynamic_import_reject(isolate, dyn_import_id, exception);
}
self.dynamic_import_module_evaluate(
isolate,
dyn_import_id,
module_id,
)?;
}
continue;
}
return Poll::Ready(Ok(()));
}
}
pub(in crate::runtime) fn evaluate_pending_module(
&self,
isolate: &mut v8::Isolate,
) {
let maybe_module_evaluation = self
.0
.context_state
.borrow_mut()
.pending_mod_evaluate
.take();
if maybe_module_evaluation.is_none() {
return;
}
let mut module_evaluation = maybe_module_evaluation.unwrap();
let state_rc = self.0.state();
let scope = &mut self.handle_scope(isolate);
let promise_global = module_evaluation.promise.clone().unwrap();
let promise = promise_global.open(scope);
let promise_state = promise.state();
match promise_state {
v8::PromiseState::Pending => {
state_rc.borrow_mut().pending_mod_evaluate = Some(module_evaluation);
}
v8::PromiseState::Fulfilled => {
scope.perform_microtask_checkpoint();
let _ = module_evaluation.sender.send(Ok(()));
module_evaluation.handled_promise_rejections.clear();
}
v8::PromiseState::Rejected => {
let exception = promise.result(scope);
scope.perform_microtask_checkpoint();
if module_evaluation
.handled_promise_rejections
.contains(&promise_global)
{
let _ = module_evaluation.sender.send(Ok(()));
module_evaluation.handled_promise_rejections.clear();
} else {
let _ = module_evaluation
.sender
.send(exception_to_err_result(scope, exception, false));
}
}
}
}
pub(in crate::runtime) fn evaluate_dyn_imports(
&self,
isolate: &mut v8::Isolate,
) -> bool {
let pending = std::mem::take(
&mut self.0.context_state.borrow_mut().pending_dyn_mod_evaluate,
);
if pending.is_empty() {
return false;
}
let mut resolved_any = false;
let mut still_pending = vec![];
for pending_dyn_evaluate in pending {
let maybe_result = {
let scope = &mut self.handle_scope(isolate);
let module_id = pending_dyn_evaluate.module_id;
let promise = pending_dyn_evaluate.promise.open(scope);
let _module = pending_dyn_evaluate.module.open(scope);
let promise_state = promise.state();
match promise_state {
v8::PromiseState::Pending => {
still_pending.push(pending_dyn_evaluate);
None
}
v8::PromiseState::Fulfilled => {
Some(Ok((pending_dyn_evaluate.load_id, module_id)))
}
v8::PromiseState::Rejected => {
let exception = promise.result(scope);
let exception = v8::Global::new(scope, exception);
Some(Err((pending_dyn_evaluate.load_id, exception)))
}
}
};
if let Some(result) = maybe_result {
resolved_any = true;
match result {
Ok((dyn_import_id, module_id)) => {
self.dynamic_import_resolve(isolate, dyn_import_id, module_id);
}
Err((dyn_import_id, exception)) => {
self.dynamic_import_reject(isolate, dyn_import_id, exception);
}
}
}
}
self.0.context_state.borrow_mut().pending_dyn_mod_evaluate = still_pending;
resolved_any
}
pub async fn load_main_module(
&self,
isolate: &mut v8::Isolate,
specifier: &ModuleSpecifier,
code: Option<ModuleCode>,
) -> Result<ModuleId, Error> {
let module_map_rc = self.0.module_map();
if let Some(code) = code {
let specifier = specifier.as_str().to_owned().into();
let scope = &mut self.handle_scope(isolate);
module_map_rc
.borrow_mut()
.new_es_module(scope, true, specifier, code, false)
.map_err(|e| match e {
ModuleError::Exception(exception) => {
let exception = v8::Local::new(scope, exception);
exception_to_err_result::<()>(scope, exception, false).unwrap_err()
}
ModuleError::Other(error) => error,
})?;
}
let mut load =
ModuleMap::load_main(module_map_rc.clone(), &specifier).await?;
while let Some(load_result) = load.next().await {
let (request, info) = load_result?;
let scope = &mut self.handle_scope(isolate);
load.register_and_recurse(scope, &request, info).map_err(
|e| match e {
ModuleError::Exception(exception) => {
let exception = v8::Local::new(scope, exception);
exception_to_err_result::<()>(scope, exception, false).unwrap_err()
}
ModuleError::Other(error) => error,
},
)?;
}
let root_id = load.root_module_id.expect("Root module should be loaded");
self.instantiate_module(isolate, root_id).map_err(|e| {
let scope = &mut self.handle_scope(isolate);
let exception = v8::Local::new(scope, e);
exception_to_err_result::<()>(scope, exception, false).unwrap_err()
})?;
Ok(root_id)
}
pub async fn load_side_module(
&self,
isolate: &mut v8::Isolate,
specifier: &ModuleSpecifier,
code: Option<ModuleCode>,
) -> Result<ModuleId, Error> {
let module_map_rc = self.0.module_map();
if let Some(code) = code {
let specifier = specifier.as_str().to_owned().into();
let scope = &mut self.handle_scope(isolate);
module_map_rc
.borrow_mut()
.new_es_module(scope, false, specifier, code, false)
.map_err(|e| match e {
ModuleError::Exception(exception) => {
let exception = v8::Local::new(scope, exception);
exception_to_err_result::<()>(scope, exception, false).unwrap_err()
}
ModuleError::Other(error) => error,
})?;
}
let mut load =
ModuleMap::load_side(module_map_rc.clone(), &specifier).await?;
while let Some(load_result) = load.next().await {
let (request, info) = load_result?;
let scope = &mut self.handle_scope(isolate);
load.register_and_recurse(scope, &request, info).map_err(
|e| match e {
ModuleError::Exception(exception) => {
let exception = v8::Local::new(scope, exception);
exception_to_err_result::<()>(scope, exception, false).unwrap_err()
}
ModuleError::Other(error) => error,
},
)?;
}
let root_id = load.root_module_id.expect("Root module should be loaded");
self.instantiate_module(isolate, root_id).map_err(|e| {
let scope = &mut self.handle_scope(isolate);
let exception = v8::Local::new(scope, e);
exception_to_err_result::<()>(scope, exception, false).unwrap_err()
})?;
Ok(root_id)
}
}
impl Drop for JsRealm {
fn drop(&mut self) {
if self.0.is_main_realm {
return;
}
if Rc::strong_count(&self.0.context) == 2 {
self
.0
.runtime_state
.borrow_mut()
.remove_realm(&self.0.context);
assert_eq!(Rc::strong_count(&self.0.context), 1);
self.0.clone().destroy();
assert_eq!(Rc::strong_count(&self.0.context_state), 1);
assert_eq!(Rc::strong_count(&self.0.module_map), 1);
}
}
}