Repository: denoland/deno_core
Pull request #347 (2023-11-23 20:38:55)

refactor(core): split module map data and recursive load out
Splitting `RecursiveModuleLoad` and `ModuleMapData` out.


Patch:
diff --git a/core/modules/map.rs b/core/modules/map.rs
index af47e1d..8769cdb 100644
--- a/core/modules/map.rs
+++ b/core/modules/map.rs
@@ -3,31 +3,31 @@ use crate::error::exception_to_err_result;
 use crate::error::generic_error;
 use crate::error::throw_type_error;
 use crate::error::to_v8_type_error;
-use crate::fast_string::FastString;
 use crate::modules::get_asserted_module_type_from_assertions;
 use crate::modules::parse_import_assertions;
+use crate::modules::recursive_load::RecursiveModuleLoad;
 use crate::modules::ImportAssertionsKind;
 use crate::modules::ModuleCode;
 use crate::modules::ModuleError;
 use crate::modules::ModuleId;
-use crate::modules::ModuleInfo;
 use crate::modules::ModuleLoadId;
 use crate::modules::ModuleLoader;
 use crate::modules::ModuleName;
 use crate::modules::ModuleRequest;
 use crate::modules::ModuleType;
 use crate::modules::NoopModuleLoader;
-use crate::modules::PrepareLoadFuture;
-use crate::modules::RecursiveModuleLoad;
 use crate::modules::ResolutionKind;
 use crate::runtime::JsRealm;
 use crate::runtime::SnapshottedData;
 use crate::JsRuntime;
+use crate::ModuleSource;
 use anyhow::Error;
 use futures::future::FutureExt;
 use futures::stream::FuturesUnordered;
 use futures::stream::StreamFuture;
+use futures::Future;
 use futures::StreamExt;
+use log::debug;
 use std::cell::Cell;
 use std::cell::RefCell;
 use std::collections::HashMap;
@@ -37,6 +37,10 @@ use std::rc::Rc;
 use std::task::Context;
 use std::task::Poll;
 
+type PrepareLoadFuture =
+  dyn Future<Output = (ModuleLoadId, Result<RecursiveModuleLoad, Error>)>;
+
+use super::module_map_data::ModuleMapData;
 use super::AssertedModuleType;
 
 pub const BOM_CHAR: &[u8] = &[0xef, 0xbb, 0xbf];
@@ -50,17 +54,6 @@ fn strip_bom(source_code: &[u8]) -> &[u8] {
   }
 }
 
-/// A symbolic module entity.
-#[derive(Debug, PartialEq)]
-pub(crate) enum SymbolicModule {
-  /// This module is an alias to another module.
-  /// This is useful such that multiple names could point to
-  /// the same underlying module (particularly due to redirects).
-  Alias(ModuleName),
-  /// This module associates with a V8 module by id.
-  Mod(ModuleId),
-}
-
 struct DynImportModEvaluate {
   load_id: ModuleLoadId,
   module_id: ModuleId,
@@ -91,114 +84,6 @@ pub(crate) struct ModuleMap {
   pub(crate) dyn_module_evaluate_idle_counter: Cell<u32>,
 }
 
-/// Map of [`ModuleName`] and [`AssertedModuleType`] to a data field.
-struct ModuleNameTypeMap<T> {
-  submaps: Vec<HashMap<ModuleName, T>>,
-  map_index: HashMap<AssertedModuleType, usize>,
-  len: usize,
-}
-
-impl<T> Default for ModuleNameTypeMap<T> {
-  fn default() -> Self {
-    Self {
-      submaps: Default::default(),
-      map_index: Default::default(),
-      len: 0,
-    }
-  }
-}
-
-impl<T> ModuleNameTypeMap<T> {
-  pub fn len(&self) -> usize {
-    self.len
-  }
-
-  fn map_index(&self, ty: &AssertedModuleType) -> Option<usize> {
-    self.map_index.get(ty).copied()
-  }
-
-  pub fn get<Q>(&self, ty: &AssertedModuleType, name: &Q) -> Option<&T>
-  where
-    ModuleName: std::borrow::Borrow<Q>,
-    Q: std::cmp::Eq + std::hash::Hash + ?Sized,
-  {
-    let Some(index) = self.map_index(ty) else {
-      return None;
-    };
-    let Some(map) = self.submaps.get(index) else {
-      return None;
-    };
-    map.get(name)
-  }
-
-  pub fn clear(&mut self) {
-    self.len = 0;
-    self.map_index.clear();
-    self.submaps.clear();
-  }
-
-  pub fn insert(
-    &mut self,
-    module_type: &AssertedModuleType,
-    name: FastString,
-    module: T,
-  ) {
-    let index = match self.map_index(module_type) {
-      Some(index) => index,
-      None => {
-        let index = self.submaps.len();
-        self.map_index.insert(module_type.clone(), index);
-        self.submaps.push(Default::default());
-        index
-      }
-    };
-
-    if self
-      .submaps
-      .get_mut(index)
-      .unwrap()
-      .insert(name, module)
-      .is_none()
-    {
-      self.len += 1;
-    }
-  }
-
-  /// Rather than providing an iterator, we provide a walk method. This is mainly because Rust
-  /// doesn't have generators.
-  pub fn walk(
-    &self,
-    mut f: impl FnMut(usize, &AssertedModuleType, &ModuleName, &T),
-  ) {
-    let mut i = 0;
-    for (ty, value) in self.map_index.iter() {
-      for (key, value) in self.submaps.get(*value).unwrap() {
-        f(i, ty, key, value);
-        i += 1;
-      }
-    }
-  }
-}
-
-#[derive(Default)]
-pub(crate) struct ModuleMapData {
-  /// Inverted index from module to index in `info`.
-  handles_inverted: HashMap<v8::Global<v8::Module>, usize>,
-  /// The handles we have loaded so far, corresponding with the [`ModuleInfo`] in `info`.
-  handles: Vec<v8::Global<v8::Module>>,
-  /// The modules we have loaded so far.
-  info: Vec<ModuleInfo>,
-  /// [`ModuleName`] to [`SymbolicModule`] for modules.
-  by_name: ModuleNameTypeMap<SymbolicModule>,
-  /// The next ID used for a load.
-  next_load_id: ModuleLoadId,
-  /// If a main module has been loaded, points to it by index.
-  main_module_id: Option<ModuleId>,
-  /// This store is used temporarily, to forward parsed JSON
-  /// value from `new_json_module` to `json_module_evaluation_steps`
-  json_value_store: HashMap<v8::Global<v8::Module>, v8::Global<v8::Value>>,
-}
-
 impl ModuleMap {
   pub(crate) fn next_load_id(&self) -> i32 {
     // TODO(mmastrac): move recursive module loading into here so we can avoid making this pub
@@ -232,246 +117,7 @@ impl ModuleMap {
     }
   }
 
-  pub fn serialize_for_snapshotting(
-    &self,
-    scope: &mut v8::HandleScope,
-  ) -> SnapshottedData {
-    let array = v8::Array::new(scope, 3);
-    let data = self.data.borrow();
-
-    let next_load_id = v8::Integer::new(scope, data.next_load_id);
-    array.set_index(scope, 0, next_load_id.into());
-
-    if let Some(main_module_id) = data.main_module_id {
-      let main_module_id = v8::Integer::new(scope, main_module_id as i32);
-      array.set_index(scope, 1, main_module_id.into());
-    }
-
-    let info_arr = v8::Array::new(scope, data.info.len() as i32);
-    for (i, info) in data.info.iter().enumerate() {
-      let module_info_arr = v8::Array::new(scope, 4);
-
-      let id = v8::Integer::new(scope, info.id as i32);
-      module_info_arr.set_index(scope, 0, id.into());
-
-      let name = info.name.v8(scope);
-      module_info_arr.set_index(scope, 1, name.into());
-
-      let array_len = 2 * info.requests.len() as i32;
-      let requests_arr = v8::Array::new(scope, array_len);
-      for (i, request) in info.requests.iter().enumerate() {
-        let specifier = v8::String::new_from_one_byte(
-          scope,
-          request.specifier.as_bytes(),
-          v8::NewStringType::Normal,
-        )
-        .unwrap();
-        requests_arr.set_index(scope, 2 * i as u32, specifier.into());
-        let value = request.asserted_module_type.to_v8(scope);
-        requests_arr.set_index(scope, (2 * i) as u32 + 1, value);
-      }
-      module_info_arr.set_index(scope, 2, requests_arr.into());
-
-      let module_type = info.module_type.to_v8(scope);
-      module_info_arr.set_index(scope, 3, module_type);
-
-      info_arr.set_index(scope, i as u32, module_info_arr.into());
-    }
-    array.set_index(scope, 2, info_arr.into());
-
-    let length = self.data.borrow().by_name.len();
-    let by_name_array = v8::Array::new(scope, length.try_into().unwrap());
-    self
-      .data
-      .borrow()
-      .by_name
-      .walk(|i, module_type, name, module| {
-        let arr = v8::Array::new(scope, 3);
-
-        let specifier = name.v8(scope);
-        arr.set_index(scope, 0, specifier.into());
-        let value = module_type.to_v8(scope);
-        arr.set_index(scope, 1, value);
-
-        let symbolic_module: v8::Local<v8::Value> = match module {
-          SymbolicModule::Alias(alias) => {
-            let alias = v8::String::new_from_one_byte(
-              scope,
-              alias.as_bytes(),
-              v8::NewStringType::Normal,
-            )
-            .unwrap();
-            alias.into()
-          }
-          SymbolicModule::Mod(id) => {
-            let id = v8::Integer::new(scope, *id as i32);
-            id.into()
-          }
-        };
-        arr.set_index(scope, 2, symbolic_module);
-
-        by_name_array.set_index(scope, i as u32, arr.into());
-      });
-    array.set_index(scope, 3, by_name_array.into());
-
-    let array_global = v8::Global::new(scope, array);
-
-    let handles = data.handles.clone();
-    SnapshottedData {
-      module_map_data: array_global,
-      module_handles: handles,
-    }
-  }
-
-  pub fn update_with_snapshotted_data(
-    &self,
-    scope: &mut v8::HandleScope,
-    snapshotted_data: SnapshottedData,
-  ) {
-    let local_data: v8::Local<v8::Array> =
-      v8::Local::new(scope, snapshotted_data.module_map_data);
-
-    {
-      let next_load_id = local_data.get_index(scope, 0).unwrap();
-      assert!(next_load_id.is_int32());
-      let integer = next_load_id.to_integer(scope).unwrap();
-      let val = integer.int32_value(scope).unwrap();
-      self.data.borrow_mut().next_load_id = val;
-    }
-
-    {
-      let main_module_id = local_data.get_index(scope, 1).unwrap();
-      if !main_module_id.is_undefined() {
-        let integer = main_module_id
-          .to_integer(scope)
-          .map(|v| v.int32_value(scope).unwrap() as usize);
-        self.data.borrow_mut().main_module_id = integer;
-      }
-    }
-
-    {
-      let info_val = local_data.get_index(scope, 2).unwrap();
-
-      let info_arr: v8::Local<v8::Array> = info_val.try_into().unwrap();
-      let len = info_arr.length() as usize;
-      // Over allocate so executing a few scripts doesn't have to resize this vec.
-      let mut info = Vec::with_capacity(len + 16);
-
-      for i in 0..len {
-        let module_info_arr: v8::Local<v8::Array> = info_arr
-          .get_index(scope, i as u32)
-          .unwrap()
-          .try_into()
-          .unwrap();
-        let id = module_info_arr
-          .get_index(scope, 0)
-          .unwrap()
-          .to_integer(scope)
-          .unwrap()
-          .value() as ModuleId;
-
-        let name = module_info_arr
-          .get_index(scope, 1)
-          .unwrap()
-          .to_rust_string_lossy(scope)
-          .into();
-
-        let requests_arr: v8::Local<v8::Array> = module_info_arr
-          .get_index(scope, 2)
-          .unwrap()
-          .try_into()
-          .unwrap();
-        let len = (requests_arr.length() as usize) / 2;
-        let mut requests = Vec::with_capacity(len);
-        for i in 0..len {
-          let specifier = requests_arr
-            .get_index(scope, (2 * i) as u32)
-            .unwrap()
-            .to_rust_string_lossy(scope);
-          let value =
-            requests_arr.get_index(scope, (2 * i + 1) as u32).unwrap();
-          let asserted_module_type =
-            AssertedModuleType::try_from_v8(scope, value).unwrap();
-          requests.push(ModuleRequest {
-            specifier,
-            asserted_module_type,
-          });
-        }
-
-        let value = module_info_arr.get_index(scope, 3).unwrap();
-        let module_type =
-          AssertedModuleType::try_from_v8(scope, value).unwrap();
-
-        let main = self.data.borrow().main_module_id == Some(id);
-        let module_info = ModuleInfo {
-          id,
-          main,
-          name,
-          requests,
-          module_type,
-        };
-        info.push(module_info);
-      }
-
-      self.data.borrow_mut().info = info;
-    }
-
-    self.data.borrow_mut().by_name.clear();
-
-    {
-      let by_name_arr: v8::Local<v8::Array> =
-        local_data.get_index(scope, 3).unwrap().try_into().unwrap();
-      let len = by_name_arr.length() as usize;
-
-      for i in 0..len {
-        let arr: v8::Local<v8::Array> = by_name_arr
-          .get_index(scope, i as u32)
-          .unwrap()
-          .try_into()
-          .unwrap();
-
-        let specifier =
-          arr.get_index(scope, 0).unwrap().to_rust_string_lossy(scope);
-        let asserted_module_type = match arr
-          .get_index(scope, 1)
-          .unwrap()
-          .to_integer(scope)
-          .unwrap()
-          .value()
-        {
-          0 => AssertedModuleType::JavaScriptOrWasm,
-          1 => AssertedModuleType::Json,
-          _ => unreachable!(),
-        };
-
-        let symbolic_module_val = arr.get_index(scope, 2).unwrap();
-        let val = if symbolic_module_val.is_number() {
-          SymbolicModule::Mod(
-            symbolic_module_val
-              .to_integer(scope)
-              .unwrap()
-              .value()
-              .try_into()
-              .unwrap(),
-          )
-        } else {
-          SymbolicModule::Alias(
-            symbolic_module_val.to_rust_string_lossy(scope).into(),
-          )
-        };
-
-        self.data.borrow_mut().by_name.insert(
-          &asserted_module_type,
-          specifier.into(),
-          val,
-        );
-      }
-    }
-
-    self.data.borrow_mut().handles = snapshotted_data.module_handles;
-  }
-
-  pub(crate) fn new(loader: Rc<dyn ModuleLoader>) -> ModuleMap {
+  pub(crate) fn new(loader: Rc<dyn ModuleLoader>) -> Self {
     Self {
       loader: loader.into(),
       dyn_module_evaluate_idle_counter: Default::default(),
@@ -486,6 +132,29 @@ impl ModuleMap {
     }
   }
 
+  pub(crate) fn new_from_snapshotted_data(
+    loader: Rc<dyn ModuleLoader>,
+    scope: &mut v8::HandleScope,
+    data: SnapshottedData,
+  ) -> Self {
+    let new = Self::new(loader);
+    new
+      .data
+      .borrow_mut()
+      .update_with_snapshotted_data(scope, data);
+    new
+  }
+
+  fn get_handle_by_name(
+    &self,
+    name: impl AsRef<str>,
+  ) -> Option<v8::Global<v8::Module>> {
+    let id = self
+      .get_id(name.as_ref(), AssertedModuleType::JavaScriptOrWasm)
+      .or_else(|| self.get_id(name.as_ref(), AssertedModuleType::Json))?;
+    self.get_handle(id)
+  }
+
   /// Get module id, following all aliases in case of module specifier
   /// that had been redirected.
   pub(crate) fn get_id(
@@ -493,24 +162,101 @@ impl ModuleMap {
     name: impl AsRef<str>,
     asserted_module_type: impl AsRef<AssertedModuleType>,
   ) -> Option<ModuleId> {
-    let map = &self.data.borrow().by_name;
-    let first_symbolic_module =
-      map.get(asserted_module_type.as_ref(), name.as_ref())?;
-    let mut mod_name = match first_symbolic_module {
-      SymbolicModule::Mod(mod_id) => return Some(*mod_id),
-      SymbolicModule::Alias(target) => target,
+    self.data.borrow().get_id(name, asserted_module_type)
+  }
+
+  pub(crate) fn is_main_module(&self, global: &v8::Global<v8::Module>) -> bool {
+    self.data.borrow().is_main_module(global)
+  }
+
+  pub(crate) fn get_name_by_module(
+    &self,
+    global: &v8::Global<v8::Module>,
+  ) -> Option<String> {
+    self.data.borrow().get_name_by_module(global)
+  }
+
+  pub(crate) fn get_name_by_id(&self, id: ModuleId) -> Option<String> {
+    self.data.borrow().get_name_by_id(id)
+  }
+
+  pub(crate) fn get_handle(
+    &self,
+    id: ModuleId,
+  ) -> Option<v8::Global<v8::Module>> {
+    self.data.borrow().get_handle(id)
+  }
+
+  pub(crate) fn serialize_for_snapshotting(
+    &self,
+    scope: &mut v8::HandleScope,
+  ) -> SnapshottedData {
+    self.data.borrow().serialize_for_snapshotting(scope)
+  }
+
+  #[cfg(test)]
+  pub fn is_alias(
+    &self,
+    name: &str,
+    asserted_module_type: impl AsRef<AssertedModuleType>,
+  ) -> bool {
+    self.data.borrow().is_alias(name, asserted_module_type)
+  }
+
+  #[cfg(test)]
+  pub fn assert_module_map(&self, modules: &Vec<super::ModuleInfo>) {
+    self.data.borrow().assert_module_map(modules);
+  }
+
+  pub(crate) fn new_module(
+    &self,
+    scope: &mut v8::HandleScope,
+    main: bool,
+    dynamic: bool,
+    module_source: ModuleSource,
+  ) -> Result<ModuleId, ModuleError> {
+    let ModuleSource {
+      code,
+      module_type,
+      module_url_found,
+      module_url_specified,
+    } = module_source;
+
+    // Register the module in the module map unless it's already there. If the
+    // specified URL and the "true" URL are different, register the alias.
+    let module_url_found = if let Some(module_url_found) = module_url_found {
+      let (module_url_found1, module_url_found2) =
+        module_url_found.into_cheap_copy();
+      self.data.borrow_mut().alias(
+        module_url_specified,
+        &module_type.into(),
+        module_url_found1,
+      );
+      module_url_found2
+    } else {
+      module_url_specified
     };
-    loop {
-      let symbolic_module =
-        map.get(asserted_module_type.as_ref(), mod_name.as_ref())?;
-      match symbolic_module {
-        SymbolicModule::Alias(target) => {
-          debug_assert!(mod_name != target);
-          mod_name = target;
-        }
-        SymbolicModule::Mod(mod_id) => return Some(*mod_id),
+
+    let asserted_module_type = AssertedModuleType::from(module_type);
+    let maybe_module_id = self.get_id(&module_url_found, asserted_module_type);
+    let module_id = match maybe_module_id {
+      Some(id) => {
+        debug!(
+          "Already-registered module fetched again: {:?}",
+          module_url_found
+        );
+        id
       }
-    }
+      None => match module_type {
+        ModuleType::JavaScript => {
+          self.new_es_module(scope, main, module_url_found, code, dynamic)?
+        }
+        ModuleType::Json => {
+          self.new_json_module(scope, module_url_found, code)?
+        }
+      },
+    };
+    Ok(module_id)
   }
 
   pub(crate) fn new_json_module(
@@ -555,8 +301,13 @@ impl ModuleMap {
       .json_value_store
       .insert(handle.clone(), value_handle);
 
-    let id =
-      self.create_module_info(name, ModuleType::Json, handle, false, vec![]);
+    let id = self.data.borrow_mut().create_module_info(
+      name,
+      ModuleType::Json,
+      handle,
+      false,
+      vec![],
+    );
 
     Ok(id)
   }
@@ -645,7 +396,7 @@ impl ModuleMap {
     if main {
       let data = self.data.borrow();
       if let Some(main_module) = data.main_module_id {
-        let main_name = self.get_name_by_id(main_module).unwrap();
+        let main_name = self.data.borrow().get_name_by_id(main_module).unwrap();
         return Err(ModuleError::Other(generic_error(
           format!("Trying to create \"main\" module ({:?}), when one already exists ({:?})",
           name.as_ref(),
@@ -655,7 +406,7 @@ impl ModuleMap {
     }
 
     let handle = v8::Global::<v8::Module>::new(tc_scope, module);
-    let id = self.create_module_info(
+    let id = self.data.borrow_mut().create_module_info(
       name,
       ModuleType::JavaScript,
       handle,
@@ -712,6 +463,8 @@ impl ModuleMap {
     let referrer_global = v8::Global::new(scope, referrer);
 
     let referrer_name = module_map
+      .data
+      .borrow()
       .get_name_by_module(&referrer_global)
       .expect("ModuleInfo not found");
 
@@ -765,54 +518,19 @@ impl ModuleMap {
     None
   }
 
-  pub(crate) fn get_handle_by_name(
-    &self,
-    name: impl AsRef<str>,
-  ) -> Option<v8::Global<v8::Module>> {
-    let id = self
-      .get_id(name.as_ref(), AssertedModuleType::JavaScriptOrWasm)
-      .or_else(|| self.get_id(name.as_ref(), AssertedModuleType::Json))?;
-    self.get_handle(id)
-  }
-
   pub(crate) fn inject_handle(
     &self,
     name: ModuleName,
     module_type: ModuleType,
     handle: v8::Global<v8::Module>,
   ) {
-    self.create_module_info(name, module_type, handle, false, vec![]);
-  }
-
-  fn create_module_info(
-    &self,
-    name: FastString,
-    module_type: ModuleType,
-    handle: v8::Global<v8::Module>,
-    main: bool,
-    requests: Vec<ModuleRequest>,
-  ) -> ModuleId {
-    let mut data = self.data.borrow_mut();
-    let id = data.handles.len();
-    let module_type = module_type.into();
-    let (name1, name2) = name.into_cheap_copy();
-    data.handles_inverted.insert(handle.clone(), id);
-    data.handles.push(handle);
-    if main {
-      data.main_module_id = Some(id);
-    }
-    data
-      .by_name
-      .insert(&module_type, name1, SymbolicModule::Mod(id));
-    data.info.push(ModuleInfo {
-      id,
-      main,
-      name: name2,
-      requests,
+    self.data.borrow_mut().create_module_info(
+      name,
       module_type,
-    });
-
-    id
+      handle,
+      false,
+      vec![],
+    );
   }
 
   pub(crate) fn get_requested_modules(
@@ -823,77 +541,6 @@ impl ModuleMap {
     self.data.borrow().info.get(id).map(|i| i.requests.clone())
   }
 
-  fn is_registered(
-    &self,
-    specifier: impl AsRef<str>,
-    asserted_module_type: impl AsRef<AssertedModuleType>,
-  ) -> bool {
-    self
-      .get_id(specifier.as_ref(), asserted_module_type.as_ref())
-      .is_some()
-  }
-
-  pub(crate) fn alias(
-    &self,
-    name: FastString,
-    asserted_module_type: &AssertedModuleType,
-    target: FastString,
-  ) {
-    debug_assert_ne!(name, target);
-    self.data.borrow_mut().by_name.insert(
-      asserted_module_type,
-      name,
-      SymbolicModule::Alias(target),
-    );
-  }
-
-  #[cfg(test)]
-  pub(crate) fn is_alias(
-    &self,
-    name: &str,
-    asserted_module_type: AssertedModuleType,
-  ) -> bool {
-    let map = &self.data.borrow().by_name;
-    let entry = map.get(&asserted_module_type, name);
-    matches!(entry, Some(SymbolicModule::Alias(_)))
-  }
-
-  pub(crate) fn get_handle(
-    &self,
-    id: ModuleId,
-  ) -> Option<v8::Global<v8::Module>> {
-    self.data.borrow().handles.get(id).cloned()
-  }
-
-  pub(crate) fn get_name_by_module(
-    &self,
-    global: &v8::Global<v8::Module>,
-  ) -> Option<String> {
-    if let Some(id) = self.data.borrow().handles_inverted.get(global) {
-      self.get_name_by_id(*id)
-    } else {
-      None
-    }
-  }
-
-  pub(crate) fn is_main_module(&self, global: &v8::Global<v8::Module>) -> bool {
-    let data = self.data.borrow();
-    data
-      .main_module_id
-      .map(|id| data.handles_inverted.get(global) == Some(&id))
-      .unwrap_or_default()
-  }
-
-  pub(crate) fn get_name_by_id(&self, id: ModuleId) -> Option<String> {
-    // TODO(mmastrac): Don't clone
-    self
-      .data
-      .borrow()
-      .info
-      .get(id)
-      .map(|info| info.name.as_str().to_owned())
-  }
-
   pub(crate) async fn load_main(
     module_map_rc: Rc<ModuleMap>,
     specifier: impl AsRef<str>,
@@ -916,7 +563,7 @@ impl ModuleMap {
 
   // Initiate loading of a module graph imported using `import()`.
   pub(crate) fn load_dynamic_import(
-    module_map_rc: Rc<ModuleMap>,
+    self: Rc<Self>,
     specifier: &str,
     referrer: &str,
     asserted_module_type: AssertedModuleType,
@@ -926,15 +573,15 @@ impl ModuleMap {
       specifier,
       referrer,
       asserted_module_type.clone(),
-      module_map_rc.clone(),
+      self.clone(),
     );
 
-    module_map_rc
+    self
       .dynamic_import_map
       .borrow_mut()
       .insert(load.id, resolver_handle);
 
-    let loader = module_map_rc.loader.clone();
+    let loader = self.loader.clone();
     let resolve_result = loader.borrow().resolve(
       specifier,
       referrer,
@@ -942,7 +589,11 @@ impl ModuleMap {
     );
     let fut = match resolve_result {
       Ok(module_specifier) => {
-        if module_map_rc.is_registered(module_specifier, asserted_module_type) {
+        if self
+          .data
+          .borrow()
+          .is_registered(module_specifier, asserted_module_type)
+        {
           async move { (load.id, Ok(load)) }.boxed_local()
         } else {
           async move { (load.id, load.prepare().await.map(|()| load)) }
@@ -951,11 +602,8 @@ impl ModuleMap {
       }
       Err(error) => async move { (load.id, Err(error)) }.boxed_local(),
     };
-    module_map_rc
-      .preparing_dynamic_imports
-      .borrow_mut()
-      .push(fut);
-    module_map_rc.preparing_dynamic_imports_pending.set(true);
+    self.preparing_dynamic_imports.borrow_mut().push(fut);
+    self.preparing_dynamic_imports_pending.set(true);
   }
 
   pub(crate) fn has_pending_dynamic_imports(&self) -> bool {
@@ -1123,6 +771,8 @@ impl ModuleMap {
     let resolver = resolver_handle.open(scope);
 
     let module = self
+      .data
+      .borrow()
       .get_handle(mod_id)
       .map(|handle| v8::Local::new(scope, handle))
       .expect("Dyn import module info not found");
@@ -1320,8 +970,11 @@ impl ModuleMap {
     scope: &mut v8::HandleScope,
     module_id: ModuleId,
   ) -> Result<v8::Global<v8::Object>, Error> {
-    let module_handle =
-      self.get_handle(module_id).expect("ModuleInfo not found");
+    let module_handle = self
+      .data
+      .borrow()
+      .get_handle(module_id)
+      .expect("ModuleInfo not found");
 
     let module = module_handle.open(scope);
 
@@ -1411,26 +1064,6 @@ impl ModuleMap {
 
     vec![]
   }
-
-  // TODO(mmastrac): this is better than giving the entire crate access to the internals.
-  #[cfg(test)]
-  pub fn assert_module_map(&self, modules: &Vec<ModuleInfo>) {
-    let data = self.data.borrow();
-    assert_eq!(data.handles.len(), modules.len());
-    assert_eq!(data.info.len(), modules.len());
-    assert_eq!(data.next_load_id as usize, modules.len());
-    assert_eq!(data.by_name.len(), modules.len());
-
-    for info in modules {
-      let data = self.data.borrow();
-      assert!(data.handles.get(info.id).is_some());
-      assert_eq!(data.info.get(info.id).unwrap(), info);
-      assert_eq!(
-        data.by_name.get(&info.module_type, &info.name),
-        Some(&SymbolicModule::Mod(info.id))
-      );
-    }
-  }
 }
 
 impl Default for ModuleMap {
diff --git a/core/modules/mod.rs b/core/modules/mod.rs
index ed50d58..7c97639 100644
--- a/core/modules/mod.rs
+++ b/core/modules/mod.rs
@@ -1,29 +1,17 @@
 // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::error::generic_error;
 use crate::fast_string::FastString;
 use crate::module_specifier::ModuleSpecifier;
-use crate::resolve_url;
 use anyhow::Error;
-use futures::future::FutureExt;
-use futures::stream::FuturesUnordered;
-use futures::stream::Stream;
-use futures::stream::TryStreamExt;
-use log::debug;
 use serde::Deserialize;
 use serde::Serialize;
 use std::borrow::Cow;
-use std::cell::RefCell;
 use std::collections::HashMap;
-use std::collections::HashSet;
-use std::collections::VecDeque;
 use std::future::Future;
-use std::pin::Pin;
-use std::rc::Rc;
-use std::task::Context;
-use std::task::Poll;
 
 mod loaders;
 mod map;
+mod module_map_data;
+mod recursive_load;
 
 #[cfg(test)]
 mod tests;
@@ -256,13 +244,8 @@ impl ModuleSource {
   }
 }
 
-pub(crate) type PrepareLoadFuture =
-  dyn Future<Output = (ModuleLoadId, Result<RecursiveModuleLoad, Error>)>;
 pub type ModuleSourceFuture = dyn Future<Output = Result<ModuleSource, Error>>;
 
-type ModuleLoadFuture =
-  dyn Future<Output = Result<Option<(ModuleRequest, ModuleSource)>, Error>>;
-
 #[derive(Debug, PartialEq, Eq)]
 pub enum ResolutionKind {
   /// This kind is used in only one situation: when a module is loaded via
@@ -278,391 +261,6 @@ pub enum ResolutionKind {
   DynamicImport,
 }
 
-/// Describes the entrypoint of a recursive module load.
-#[derive(Debug)]
-enum LoadInit {
-  /// Main module specifier.
-  Main(String),
-  /// Module specifier for side module.
-  Side(String),
-  /// Dynamic import specifier with referrer and expected
-  /// module type (which is determined by import assertion).
-  DynamicImport(String, String, AssertedModuleType),
-}
-
-#[derive(Debug, Eq, PartialEq)]
-pub enum LoadState {
-  Init,
-  LoadingRoot,
-  LoadingImports,
-  Done,
-}
-
-/// This future is used to implement parallel async module loading.
-pub(crate) struct RecursiveModuleLoad {
-  pub id: ModuleLoadId,
-  pub root_module_id: Option<ModuleId>,
-  init: LoadInit,
-  root_asserted_module_type: Option<AssertedModuleType>,
-  state: LoadState,
-  module_map_rc: Rc<ModuleMap>,
-  pending: FuturesUnordered<Pin<Box<ModuleLoadFuture>>>,
-  visited: HashSet<ModuleRequest>,
-  visited_as_alias: Rc<RefCell<HashSet<String>>>,
-  // The loader is copied from `module_map_rc`, but its reference is cloned
-  // ahead of time to avoid already-borrowed errors.
-  loader: Rc<dyn ModuleLoader>,
-}
-
-impl RecursiveModuleLoad {
-  /// Starts a new asynchronous load of the module graph for given specifier.
-  ///
-  /// The module corresponding for the given `specifier` will be marked as
-  // "the main module" (`import.meta.main` will return `true` for this module).
-  fn main(specifier: &str, module_map_rc: Rc<ModuleMap>) -> Self {
-    Self::new(LoadInit::Main(specifier.to_string()), module_map_rc)
-  }
-
-  /// Starts a new asynchronous load of the module graph for given specifier.
-  fn side(specifier: &str, module_map_rc: Rc<ModuleMap>) -> Self {
-    Self::new(LoadInit::Side(specifier.to_string()), module_map_rc)
-  }
-
-  /// Starts a new asynchronous load of the module graph for given specifier
-  /// that was imported using `import()`.
-  fn dynamic_import(
-    specifier: &str,
-    referrer: &str,
-    asserted_module_type: AssertedModuleType,
-    module_map_rc: Rc<ModuleMap>,
-  ) -> Self {
-    Self::new(
-      LoadInit::DynamicImport(
-        specifier.to_string(),
-        referrer.to_string(),
-        asserted_module_type,
-      ),
-      module_map_rc,
-    )
-  }
-
-  fn new(init: LoadInit, module_map_rc: Rc<ModuleMap>) -> Self {
-    let id = module_map_rc.next_load_id();
-    let loader = module_map_rc.loader.borrow().clone();
-    let asserted_module_type = match &init {
-      LoadInit::DynamicImport(_, _, module_type) => module_type.clone(),
-      _ => AssertedModuleType::JavaScriptOrWasm,
-    };
-    let mut load = Self {
-      id,
-      root_module_id: None,
-      root_asserted_module_type: None,
-      init,
-      state: LoadState::Init,
-      module_map_rc: module_map_rc.clone(),
-      loader,
-      pending: FuturesUnordered::new(),
-      visited: HashSet::new(),
-      visited_as_alias: Default::default(),
-    };
-    // FIXME(bartlomieju): this seems fishy
-    // Ignore the error here, let it be hit in `Stream::poll_next()`.
-    if let Ok(root_specifier) = load.resolve_root() {
-      if let Some(module_id) =
-        module_map_rc.get_id(root_specifier, &asserted_module_type)
-      {
-        load.root_module_id = Some(module_id);
-        load.root_asserted_module_type = Some(asserted_module_type);
-      }
-    }
-    load
-  }
-
-  fn resolve_root(&self) -> Result<ModuleSpecifier, Error> {
-    match self.init {
-      LoadInit::Main(ref specifier) => {
-        self
-          .loader
-          .resolve(specifier, ".", ResolutionKind::MainModule)
-      }
-      LoadInit::Side(ref specifier) => {
-        self.loader.resolve(specifier, ".", ResolutionKind::Import)
-      }
-      LoadInit::DynamicImport(ref specifier, ref referrer, _) => self
-        .loader
-        .resolve(specifier, referrer, ResolutionKind::DynamicImport),
-    }
-  }
-
-  async fn prepare(&self) -> Result<(), Error> {
-    let (module_specifier, maybe_referrer) = match self.init {
-      LoadInit::Main(ref specifier) => {
-        let spec =
-          self
-            .loader
-            .resolve(specifier, ".", ResolutionKind::MainModule)?;
-        (spec, None)
-      }
-      LoadInit::Side(ref specifier) => {
-        let spec =
-          self
-            .loader
-            .resolve(specifier, ".", ResolutionKind::Import)?;
-        (spec, None)
-      }
-      LoadInit::DynamicImport(ref specifier, ref referrer, _) => {
-        let spec = self.loader.resolve(
-          specifier,
-          referrer,
-          ResolutionKind::DynamicImport,
-        )?;
-        (spec, Some(referrer.to_string()))
-      }
-    };
-
-    self
-      .loader
-      .prepare_load(&module_specifier, maybe_referrer, self.is_dynamic_import())
-      .await
-  }
-
-  fn is_currently_loading_main_module(&self) -> bool {
-    !self.is_dynamic_import()
-      && matches!(self.init, LoadInit::Main(..))
-      && self.state == LoadState::LoadingRoot
-  }
-
-  fn is_dynamic_import(&self) -> bool {
-    matches!(self.init, LoadInit::DynamicImport(..))
-  }
-
-  pub(crate) fn register_and_recurse(
-    &mut self,
-    scope: &mut v8::HandleScope,
-    module_request: &ModuleRequest,
-    module_source: ModuleSource,
-  ) -> Result<(), ModuleError> {
-    let expected_asserted_module_type = module_source.module_type.into();
-    let module_url_found = module_source.module_url_found;
-    let module_url_specified = module_source.module_url_specified;
-
-    if module_request.asserted_module_type != expected_asserted_module_type {
-      return Err(ModuleError::Other(generic_error(format!(
-        "Expected a \"{}\" module but loaded a \"{}\" module.",
-        module_request.asserted_module_type, module_source.module_type,
-      ))));
-    }
-
-    // Register the module in the module map unless it's already there. If the
-    // specified URL and the "true" URL are different, register the alias.
-    let module_url_found = if let Some(module_url_found) = module_url_found {
-      let (module_url_found1, module_url_found2) =
-        module_url_found.into_cheap_copy();
-      self.module_map_rc.alias(
-        module_url_specified,
-        &expected_asserted_module_type,
-        module_url_found1,
-      );
-      module_url_found2
-    } else {
-      module_url_specified
-    };
-
-    let maybe_module_id = self
-      .module_map_rc
-      .get_id(&module_url_found, &expected_asserted_module_type);
-    let module_id = match maybe_module_id {
-      Some(id) => {
-        debug!(
-          "Already-registered module fetched again: {:?}",
-          module_url_found
-        );
-        id
-      }
-      None => match module_source.module_type {
-        ModuleType::JavaScript => self.module_map_rc.new_es_module(
-          scope,
-          self.is_currently_loading_main_module(),
-          module_url_found,
-          module_source.code,
-          self.is_dynamic_import(),
-        )?,
-        ModuleType::Json => self.module_map_rc.new_json_module(
-          scope,
-          module_url_found,
-          module_source.code,
-        )?,
-      },
-    };
-
-    self.register_and_recurse_inner(module_id, module_request);
-
-    // Update `self.state` however applicable.
-    if self.state == LoadState::LoadingRoot {
-      self.root_module_id = Some(module_id);
-      self.root_asserted_module_type = Some(module_source.module_type.into());
-      self.state = LoadState::LoadingImports;
-    }
-    if self.pending.is_empty() {
-      self.state = LoadState::Done;
-    }
-
-    Ok(())
-  }
-
-  fn register_and_recurse_inner(
-    &mut self,
-    module_id: usize,
-    module_request: &ModuleRequest,
-  ) {
-    // Recurse the module's imports. There are two cases for each import:
-    // 1. If the module is not in the module map, start a new load for it in
-    //    `self.pending`. The result of that load should eventually be passed to
-    //    this function for recursion.
-    // 2. If the module is already in the module map, queue it up to be
-    //    recursed synchronously here.
-    // This robustly ensures that the whole graph is in the module map before
-    // `LoadState::Done` is set.
-    let mut already_registered = VecDeque::new();
-    already_registered.push_back((module_id, module_request.clone()));
-    self.visited.insert(module_request.clone());
-    while let Some((module_id, module_request)) = already_registered.pop_front()
-    {
-      let referrer = ModuleSpecifier::parse(&module_request.specifier).unwrap();
-      let imports = self
-        .module_map_rc
-        .get_requested_modules(module_id)
-        .unwrap()
-        .clone();
-      for module_request in imports {
-        if !self.visited.contains(&module_request)
-          && !self
-            .visited_as_alias
-            .borrow()
-            .contains(&module_request.specifier)
-        {
-          if let Some(module_id) = self.module_map_rc.get_id(
-            module_request.specifier.as_str(),
-            &module_request.asserted_module_type,
-          ) {
-            already_registered.push_back((module_id, module_request.clone()));
-          } else {
-            let request = module_request.clone();
-            let specifier =
-              ModuleSpecifier::parse(&module_request.specifier).unwrap();
-            let visited_as_alias = self.visited_as_alias.clone();
-            let referrer = referrer.clone();
-            let loader = self.loader.clone();
-            let is_dynamic_import = self.is_dynamic_import();
-            let fut = async move {
-              // `visited_as_alias` unlike `visited` is checked as late as
-              // possible because it can only be populated after completed
-              // loads, meaning a duplicate load future may have already been
-              // dispatched before we know it's a duplicate.
-              if visited_as_alias.borrow().contains(specifier.as_str()) {
-                return Ok(None);
-              }
-              let load_result = loader
-                .load(&specifier, Some(&referrer), is_dynamic_import)
-                .await;
-              if let Ok(source) = &load_result {
-                if let Some(found_specifier) = &source.module_url_found {
-                  visited_as_alias
-                    .borrow_mut()
-                    .insert(found_specifier.as_str().to_string());
-                }
-              }
-              load_result.map(|s| Some((request, s)))
-            };
-            self.pending.push(fut.boxed_local());
-          }
-          self.visited.insert(module_request);
-        }
-      }
-    }
-  }
-}
-
-impl Stream for RecursiveModuleLoad {
-  type Item = Result<(ModuleRequest, ModuleSource), Error>;
-
-  fn poll_next(
-    self: Pin<&mut Self>,
-    cx: &mut Context,
-  ) -> Poll<Option<Self::Item>> {
-    let inner = self.get_mut();
-    // IMPORTANT: Do not borrow `inner.module_map_rc` here. It may not be
-    // available.
-    match inner.state {
-      LoadState::Init => {
-        let module_specifier = match inner.resolve_root() {
-          Ok(url) => url,
-          Err(error) => return Poll::Ready(Some(Err(error))),
-        };
-        let asserted_module_type = match &inner.init {
-          LoadInit::DynamicImport(_, _, module_type) => module_type.clone(),
-          _ => AssertedModuleType::JavaScriptOrWasm,
-        };
-        let module_request = ModuleRequest {
-          specifier: module_specifier.to_string(),
-          asserted_module_type,
-        };
-        let load_fut = if let Some(module_id) = inner.root_module_id {
-          // If the inner future is already in the map, we might be done (assuming there are no pending
-          // loads).
-          inner.register_and_recurse_inner(module_id, &module_request);
-          if inner.pending.is_empty() {
-            inner.state = LoadState::Done;
-          } else {
-            inner.state = LoadState::LoadingImports;
-          }
-          // Internally re-poll using the new state to avoid spinning the event loop again.
-          return Self::poll_next(Pin::new(inner), cx);
-        } else {
-          let maybe_referrer = match inner.init {
-            LoadInit::DynamicImport(_, ref referrer, _) => {
-              resolve_url(referrer).ok()
-            }
-            _ => None,
-          };
-          let loader = inner.loader.clone();
-          let is_dynamic_import = inner.is_dynamic_import();
-          async move {
-            let result = loader
-              .load(
-                &module_specifier,
-                maybe_referrer.as_ref(),
-                is_dynamic_import,
-              )
-              .await;
-            result.map(|s| Some((module_request, s)))
-          }
-          .boxed_local()
-        };
-        inner.pending.push(load_fut);
-        inner.state = LoadState::LoadingRoot;
-        inner.try_poll_next_unpin(cx)
-      }
-      LoadState::LoadingRoot | LoadState::LoadingImports => {
-        match inner.pending.try_poll_next_unpin(cx)? {
-          Poll::Ready(None) => unreachable!(),
-          Poll::Ready(Some(None)) => {
-            if inner.pending.is_empty() {
-              inner.state = LoadState::Done;
-              Poll::Ready(None)
-            } else {
-              Poll::Pending
-            }
-          }
-          Poll::Ready(Some(Some(info))) => Poll::Ready(Some(Ok(info))),
-          Poll::Pending => Poll::Pending,
-        }
-      }
-      LoadState::Done => Poll::Ready(None),
-    }
-  }
-}
-
 #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
 #[repr(u8)]
 pub(crate) enum AssertedModuleType {
diff --git a/core/modules/module_map_data.rs b/core/modules/module_map_data.rs
new file mode 100644
index 0000000..cf1d1f4
--- /dev/null
+++ b/core/modules/module_map_data.rs
@@ -0,0 +1,508 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+use super::AssertedModuleType;
+use crate::fast_string::FastString;
+use crate::modules::ModuleId;
+use crate::modules::ModuleInfo;
+use crate::modules::ModuleLoadId;
+use crate::modules::ModuleName;
+use crate::modules::ModuleRequest;
+use crate::modules::ModuleType;
+use crate::runtime::SnapshottedData;
+use std::collections::HashMap;
+
+/// A symbolic module entity.
+#[derive(Debug, PartialEq)]
+pub(crate) enum SymbolicModule {
+  /// This module is an alias to another module.
+  /// This is useful such that multiple names could point to
+  /// the same underlying module (particularly due to redirects).
+  Alias(ModuleName),
+  /// This module associates with a V8 module by id.
+  Mod(ModuleId),
+}
+
+/// Map of [`ModuleName`] and [`AssertedModuleType`] to a data field.
+struct ModuleNameTypeMap<T> {
+  submaps: Vec<HashMap<ModuleName, T>>,
+  map_index: HashMap<AssertedModuleType, usize>,
+  len: usize,
+}
+
+impl<T> Default for ModuleNameTypeMap<T> {
+  fn default() -> Self {
+    Self {
+      submaps: Default::default(),
+      map_index: Default::default(),
+      len: 0,
+    }
+  }
+}
+
+impl<T> ModuleNameTypeMap<T> {
+  pub fn len(&self) -> usize {
+    self.len
+  }
+
+  fn map_index(&self, ty: &AssertedModuleType) -> Option<usize> {
+    self.map_index.get(ty).copied()
+  }
+
+  pub fn get<Q>(&self, ty: &AssertedModuleType, name: &Q) -> Option<&T>
+  where
+    ModuleName: std::borrow::Borrow<Q>,
+    Q: std::cmp::Eq + std::hash::Hash + ?Sized,
+  {
+    let Some(index) = self.map_index(ty) else {
+      return None;
+    };
+    let Some(map) = self.submaps.get(index) else {
+      return None;
+    };
+    map.get(name)
+  }
+
+  pub fn clear(&mut self) {
+    self.len = 0;
+    self.map_index.clear();
+    self.submaps.clear();
+  }
+
+  pub fn insert(
+    &mut self,
+    module_type: &AssertedModuleType,
+    name: FastString,
+    module: T,
+  ) {
+    let index = match self.map_index(module_type) {
+      Some(index) => index,
+      None => {
+        let index = self.submaps.len();
+        self.map_index.insert(module_type.clone(), index);
+        self.submaps.push(Default::default());
+        index
+      }
+    };
+
+    if self
+      .submaps
+      .get_mut(index)
+      .unwrap()
+      .insert(name, module)
+      .is_none()
+    {
+      self.len += 1;
+    }
+  }
+
+  /// Rather than providing an iterator, we provide a walk method. This is mainly because Rust
+  /// doesn't have generators.
+  pub fn walk(
+    &self,
+    mut f: impl FnMut(usize, &AssertedModuleType, &ModuleName, &T),
+  ) {
+    let mut i = 0;
+    for (ty, value) in self.map_index.iter() {
+      for (key, value) in self.submaps.get(*value).unwrap() {
+        f(i, ty, key, value);
+        i += 1;
+      }
+    }
+  }
+}
+
+#[derive(Default)]
+pub(crate) struct ModuleMapData {
+  /// Inverted index from module to index in `info`.
+  pub(crate) handles_inverted: HashMap<v8::Global<v8::Module>, usize>,
+  /// The handles we have loaded so far, corresponding with the [`ModuleInfo`] in `info`.
+  pub(crate) handles: Vec<v8::Global<v8::Module>>,
+  /// The modules we have loaded so far.
+  pub(crate) info: Vec<ModuleInfo>,
+  /// [`ModuleName`] to [`SymbolicModule`] for modules.
+  by_name: ModuleNameTypeMap<SymbolicModule>,
+  /// The next ID used for a load.
+  pub(crate) next_load_id: ModuleLoadId,
+  /// If a main module has been loaded, points to it by index.
+  pub(crate) main_module_id: Option<ModuleId>,
+  /// This store is used temporarily, to forward parsed JSON
+  /// value from `new_json_module` to `json_module_evaluation_steps`
+  pub(crate) json_value_store:
+    HashMap<v8::Global<v8::Module>, v8::Global<v8::Value>>,
+}
+
+impl ModuleMapData {
+  pub fn create_module_info(
+    &mut self,
+    name: FastString,
+    module_type: ModuleType,
+    handle: v8::Global<v8::Module>,
+    main: bool,
+    requests: Vec<ModuleRequest>,
+  ) -> ModuleId {
+    let data = self;
+    let id = data.handles.len();
+    let module_type = module_type.into();
+    let (name1, name2) = name.into_cheap_copy();
+    data.handles_inverted.insert(handle.clone(), id);
+    data.handles.push(handle);
+    if main {
+      data.main_module_id = Some(id);
+    }
+    data
+      .by_name
+      .insert(&module_type, name1, SymbolicModule::Mod(id));
+    data.info.push(ModuleInfo {
+      id,
+      main,
+      name: name2,
+      requests,
+      module_type,
+    });
+
+    id
+  }
+
+  /// Get module id, following all aliases in case of module specifier
+  /// that had been redirected.
+  pub fn get_id(
+    &self,
+    name: impl AsRef<str>,
+    asserted_module_type: impl AsRef<AssertedModuleType>,
+  ) -> Option<ModuleId> {
+    let map = &self.by_name;
+    let first_symbolic_module =
+      map.get(asserted_module_type.as_ref(), name.as_ref())?;
+    let mut mod_name = match first_symbolic_module {
+      SymbolicModule::Mod(mod_id) => return Some(*mod_id),
+      SymbolicModule::Alias(target) => target,
+    };
+    loop {
+      let symbolic_module =
+        map.get(asserted_module_type.as_ref(), mod_name.as_ref())?;
+      match symbolic_module {
+        SymbolicModule::Alias(target) => {
+          debug_assert!(mod_name != target);
+          mod_name = target;
+        }
+        SymbolicModule::Mod(mod_id) => return Some(*mod_id),
+      }
+    }
+  }
+
+  pub fn is_registered(
+    &self,
+    specifier: impl AsRef<str>,
+    asserted_module_type: impl AsRef<AssertedModuleType>,
+  ) -> bool {
+    self
+      .get_id(specifier.as_ref(), asserted_module_type.as_ref())
+      .is_some()
+  }
+
+  pub(crate) fn alias(
+    &mut self,
+    name: FastString,
+    asserted_module_type: &AssertedModuleType,
+    target: FastString,
+  ) {
+    debug_assert_ne!(name, target);
+    self.by_name.insert(
+      asserted_module_type,
+      name,
+      SymbolicModule::Alias(target),
+    );
+  }
+
+  #[cfg(test)]
+  pub(crate) fn is_alias(
+    &self,
+    name: &str,
+    asserted_module_type: impl AsRef<AssertedModuleType>,
+  ) -> bool {
+    let map = &self.by_name;
+    let entry = map.get(asserted_module_type.as_ref(), name);
+    matches!(entry, Some(SymbolicModule::Alias(_)))
+  }
+
+  pub(crate) fn get_handle(
+    &self,
+    id: ModuleId,
+  ) -> Option<v8::Global<v8::Module>> {
+    self.handles.get(id).cloned()
+  }
+
+  pub(crate) fn get_name_by_module(
+    &self,
+    global: &v8::Global<v8::Module>,
+  ) -> Option<String> {
+    if let Some(id) = self.handles_inverted.get(global) {
+      self.get_name_by_id(*id)
+    } else {
+      None
+    }
+  }
+
+  pub(crate) fn is_main_module(&self, global: &v8::Global<v8::Module>) -> bool {
+    self
+      .main_module_id
+      .map(|id| self.handles_inverted.get(global) == Some(&id))
+      .unwrap_or_default()
+  }
+
+  pub(crate) fn get_name_by_id(&self, id: ModuleId) -> Option<String> {
+    // TODO(mmastrac): Don't clone
+    self.info.get(id).map(|info| info.name.as_str().to_owned())
+  }
+
+  pub fn serialize_for_snapshotting(
+    &self,
+    scope: &mut v8::HandleScope,
+  ) -> SnapshottedData {
+    let data = self;
+    let array = v8::Array::new(scope, 3);
+
+    let next_load_id = v8::Integer::new(scope, data.next_load_id);
+    array.set_index(scope, 0, next_load_id.into());
+
+    if let Some(main_module_id) = data.main_module_id {
+      let main_module_id = v8::Integer::new(scope, main_module_id as i32);
+      array.set_index(scope, 1, main_module_id.into());
+    }
+
+    let info_arr = v8::Array::new(scope, data.info.len() as i32);
+    for (i, info) in data.info.iter().enumerate() {
+      let module_info_arr = v8::Array::new(scope, 4);
+
+      let id = v8::Integer::new(scope, info.id as i32);
+      module_info_arr.set_index(scope, 0, id.into());
+
+      let name = info.name.v8(scope);
+      module_info_arr.set_index(scope, 1, name.into());
+
+      let array_len = 2 * info.requests.len() as i32;
+      let requests_arr = v8::Array::new(scope, array_len);
+      for (i, request) in info.requests.iter().enumerate() {
+        let specifier = v8::String::new_from_one_byte(
+          scope,
+          request.specifier.as_bytes(),
+          v8::NewStringType::Normal,
+        )
+        .unwrap();
+        requests_arr.set_index(scope, 2 * i as u32, specifier.into());
+        let value = request.asserted_module_type.to_v8(scope);
+        requests_arr.set_index(scope, (2 * i) as u32 + 1, value);
+      }
+      module_info_arr.set_index(scope, 2, requests_arr.into());
+
+      let module_type = info.module_type.to_v8(scope);
+      module_info_arr.set_index(scope, 3, module_type);
+
+      info_arr.set_index(scope, i as u32, module_info_arr.into());
+    }
+    array.set_index(scope, 2, info_arr.into());
+
+    let length = self.by_name.len();
+    let by_name_array = v8::Array::new(scope, length.try_into().unwrap());
+    self.by_name.walk(|i, module_type, name, module| {
+      let arr = v8::Array::new(scope, 3);
+
+      let specifier = name.v8(scope);
+      arr.set_index(scope, 0, specifier.into());
+      let value = module_type.to_v8(scope);
+      arr.set_index(scope, 1, value);
+
+      let symbolic_module: v8::Local<v8::Value> = match module {
+        SymbolicModule::Alias(alias) => {
+          let alias = v8::String::new_from_one_byte(
+            scope,
+            alias.as_bytes(),
+            v8::NewStringType::Normal,
+          )
+          .unwrap();
+          alias.into()
+        }
+        SymbolicModule::Mod(id) => {
+          let id = v8::Integer::new(scope, *id as i32);
+          id.into()
+        }
+      };
+      arr.set_index(scope, 2, symbolic_module);
+
+      by_name_array.set_index(scope, i as u32, arr.into());
+    });
+    array.set_index(scope, 3, by_name_array.into());
+
+    let array_global = v8::Global::new(scope, array);
+
+    let handles = data.handles.clone();
+    SnapshottedData {
+      module_map_data: array_global,
+      module_handles: handles,
+    }
+  }
+
+  pub fn update_with_snapshotted_data(
+    &mut self,
+    scope: &mut v8::HandleScope,
+    snapshotted_data: SnapshottedData,
+  ) {
+    let local_data: v8::Local<v8::Array> =
+      v8::Local::new(scope, snapshotted_data.module_map_data);
+
+    {
+      let next_load_id = local_data.get_index(scope, 0).unwrap();
+      assert!(next_load_id.is_int32());
+      let integer = next_load_id.to_integer(scope).unwrap();
+      let val = integer.int32_value(scope).unwrap();
+      self.next_load_id = val;
+    }
+
+    {
+      let main_module_id = local_data.get_index(scope, 1).unwrap();
+      if !main_module_id.is_undefined() {
+        let integer = main_module_id
+          .to_integer(scope)
+          .map(|v| v.int32_value(scope).unwrap() as usize);
+        self.main_module_id = integer;
+      }
+    }
+
+    {
+      let info_val = local_data.get_index(scope, 2).unwrap();
+
+      let info_arr: v8::Local<v8::Array> = info_val.try_into().unwrap();
+      let len = info_arr.length() as usize;
+      // Over allocate so executing a few scripts doesn't have to resize this vec.
+      let mut info = Vec::with_capacity(len + 16);
+
+      for i in 0..len {
+        let module_info_arr: v8::Local<v8::Array> = info_arr
+          .get_index(scope, i as u32)
+          .unwrap()
+          .try_into()
+          .unwrap();
+        let id = module_info_arr
+          .get_index(scope, 0)
+          .unwrap()
+          .to_integer(scope)
+          .unwrap()
+          .value() as ModuleId;
+
+        let name = module_info_arr
+          .get_index(scope, 1)
+          .unwrap()
+          .to_rust_string_lossy(scope)
+          .into();
+
+        let requests_arr: v8::Local<v8::Array> = module_info_arr
+          .get_index(scope, 2)
+          .unwrap()
+          .try_into()
+          .unwrap();
+        let len = (requests_arr.length() as usize) / 2;
+        let mut requests = Vec::with_capacity(len);
+        for i in 0..len {
+          let specifier = requests_arr
+            .get_index(scope, (2 * i) as u32)
+            .unwrap()
+            .to_rust_string_lossy(scope);
+          let value =
+            requests_arr.get_index(scope, (2 * i + 1) as u32).unwrap();
+          let asserted_module_type =
+            AssertedModuleType::try_from_v8(scope, value).unwrap();
+          requests.push(ModuleRequest {
+            specifier,
+            asserted_module_type,
+          });
+        }
+
+        let value = module_info_arr.get_index(scope, 3).unwrap();
+        let module_type =
+          AssertedModuleType::try_from_v8(scope, value).unwrap();
+
+        let main = self.main_module_id == Some(id);
+        let module_info = ModuleInfo {
+          id,
+          main,
+          name,
+          requests,
+          module_type,
+        };
+        info.push(module_info);
+      }
+
+      self.info = info;
+    }
+
+    self.by_name.clear();
+
+    {
+      let by_name_arr: v8::Local<v8::Array> =
+        local_data.get_index(scope, 3).unwrap().try_into().unwrap();
+      let len = by_name_arr.length() as usize;
+
+      for i in 0..len {
+        let arr: v8::Local<v8::Array> = by_name_arr
+          .get_index(scope, i as u32)
+          .unwrap()
+          .try_into()
+          .unwrap();
+
+        let specifier =
+          arr.get_index(scope, 0).unwrap().to_rust_string_lossy(scope);
+        let asserted_module_type = match arr
+          .get_index(scope, 1)
+          .unwrap()
+          .to_integer(scope)
+          .unwrap()
+          .value()
+        {
+          0 => AssertedModuleType::JavaScriptOrWasm,
+          1 => AssertedModuleType::Json,
+          _ => unreachable!(),
+        };
+
+        let symbolic_module_val = arr.get_index(scope, 2).unwrap();
+        let val = if symbolic_module_val.is_number() {
+          SymbolicModule::Mod(
+            symbolic_module_val
+              .to_integer(scope)
+              .unwrap()
+              .value()
+              .try_into()
+              .unwrap(),
+          )
+        } else {
+          SymbolicModule::Alias(
+            symbolic_module_val.to_rust_string_lossy(scope).into(),
+          )
+        };
+
+        self
+          .by_name
+          .insert(&asserted_module_type, specifier.into(), val);
+      }
+    }
+
+    self.handles = snapshotted_data.module_handles;
+  }
+
+  // TODO(mmastrac): this is better than giving the entire crate access to the internals.
+  #[cfg(test)]
+  pub fn assert_module_map(&self, modules: &Vec<ModuleInfo>) {
+    let data = self;
+    assert_eq!(data.handles.len(), modules.len());
+    assert_eq!(data.info.len(), modules.len());
+    assert_eq!(data.next_load_id as usize, modules.len());
+    assert_eq!(data.by_name.len(), modules.len());
+
+    for info in modules {
+      assert!(data.handles.get(info.id).is_some());
+      assert_eq!(data.info.get(info.id).unwrap(), info);
+      assert_eq!(
+        data.by_name.get(&info.module_type, &info.name),
+        Some(&SymbolicModule::Mod(info.id))
+      );
+    }
+  }
+}
diff --git a/core/modules/recursive_load.rs b/core/modules/recursive_load.rs
new file mode 100644
index 0000000..380d82f
--- /dev/null
+++ b/core/modules/recursive_load.rs
@@ -0,0 +1,376 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+use crate::error::generic_error;
+use crate::module_specifier::ModuleSpecifier;
+use crate::modules::map::ModuleMap;
+use crate::modules::AssertedModuleType;
+use crate::modules::ModuleError;
+use crate::modules::ModuleId;
+use crate::modules::ModuleLoadId;
+use crate::modules::ModuleRequest;
+use crate::modules::ResolutionKind;
+use crate::resolve_url;
+use crate::ModuleLoader;
+use crate::ModuleSource;
+use anyhow::Error;
+use futures::future::FutureExt;
+use futures::stream::FuturesUnordered;
+use futures::stream::Stream;
+use futures::stream::TryStreamExt;
+use std::cell::RefCell;
+use std::collections::HashSet;
+use std::collections::VecDeque;
+use std::future::Future;
+use std::pin::Pin;
+use std::rc::Rc;
+use std::task::Context;
+use std::task::Poll;
+
+type ModuleLoadFuture =
+  dyn Future<Output = Result<Option<(ModuleRequest, ModuleSource)>, Error>>;
+
+/// Describes the entrypoint of a recursive module load.
+#[derive(Debug)]
+enum LoadInit {
+  /// Main module specifier.
+  Main(String),
+  /// Module specifier for side module.
+  Side(String),
+  /// Dynamic import specifier with referrer and expected
+  /// module type (which is determined by import assertion).
+  DynamicImport(String, String, AssertedModuleType),
+}
+
+#[derive(Debug, Eq, PartialEq)]
+enum LoadState {
+  Init,
+  LoadingRoot,
+  LoadingImports,
+  Done,
+}
+
+/// This future is used to implement parallel async module loading.
+pub(crate) struct RecursiveModuleLoad {
+  pub id: ModuleLoadId,
+  pub root_module_id: Option<ModuleId>,
+  init: LoadInit,
+  root_asserted_module_type: Option<AssertedModuleType>,
+  state: LoadState,
+  module_map_rc: Rc<ModuleMap>,
+  pending: FuturesUnordered<Pin<Box<ModuleLoadFuture>>>,
+  visited: HashSet<ModuleRequest>,
+  visited_as_alias: Rc<RefCell<HashSet<String>>>,
+  // The loader is copied from `module_map_rc`, but its reference is cloned
+  // ahead of time to avoid already-borrowed errors.
+  loader: Rc<dyn ModuleLoader>,
+}
+
+impl RecursiveModuleLoad {
+  /// Starts a new asynchronous load of the module graph for given specifier.
+  ///
+  /// The module corresponding for the given `specifier` will be marked as
+  // "the main module" (`import.meta.main` will return `true` for this module).
+  pub(crate) fn main(specifier: &str, module_map_rc: Rc<ModuleMap>) -> Self {
+    Self::new(LoadInit::Main(specifier.to_string()), module_map_rc)
+  }
+
+  /// Starts a new asynchronous load of the module graph for given specifier.
+  pub(crate) fn side(specifier: &str, module_map_rc: Rc<ModuleMap>) -> Self {
+    Self::new(LoadInit::Side(specifier.to_string()), module_map_rc)
+  }
+
+  /// Starts a new asynchronous load of the module graph for given specifier
+  /// that was imported using `import()`.
+  pub(crate) fn dynamic_import(
+    specifier: &str,
+    referrer: &str,
+    asserted_module_type: AssertedModuleType,
+    module_map_rc: Rc<ModuleMap>,
+  ) -> Self {
+    Self::new(
+      LoadInit::DynamicImport(
+        specifier.to_string(),
+        referrer.to_string(),
+        asserted_module_type,
+      ),
+      module_map_rc,
+    )
+  }
+
+  fn new(init: LoadInit, module_map_rc: Rc<ModuleMap>) -> Self {
+    let id = module_map_rc.next_load_id();
+    let loader = module_map_rc.loader.borrow().clone();
+    let asserted_module_type = match &init {
+      LoadInit::DynamicImport(_, _, module_type) => module_type.clone(),
+      _ => AssertedModuleType::JavaScriptOrWasm,
+    };
+    let mut load = Self {
+      id,
+      root_module_id: None,
+      root_asserted_module_type: None,
+      init,
+      state: LoadState::Init,
+      module_map_rc: module_map_rc.clone(),
+      loader,
+      pending: FuturesUnordered::new(),
+      visited: HashSet::new(),
+      visited_as_alias: Default::default(),
+    };
+    // FIXME(bartlomieju): this seems fishy
+    // Ignore the error here, let it be hit in `Stream::poll_next()`.
+    if let Ok(root_specifier) = load.resolve_root() {
+      if let Some(module_id) =
+        module_map_rc.get_id(root_specifier, &asserted_module_type)
+      {
+        load.root_module_id = Some(module_id);
+        load.root_asserted_module_type = Some(asserted_module_type);
+      }
+    }
+    load
+  }
+
+  fn resolve_root(&self) -> Result<ModuleSpecifier, Error> {
+    match self.init {
+      LoadInit::Main(ref specifier) => {
+        self
+          .loader
+          .resolve(specifier, ".", ResolutionKind::MainModule)
+      }
+      LoadInit::Side(ref specifier) => {
+        self.loader.resolve(specifier, ".", ResolutionKind::Import)
+      }
+      LoadInit::DynamicImport(ref specifier, ref referrer, _) => self
+        .loader
+        .resolve(specifier, referrer, ResolutionKind::DynamicImport),
+    }
+  }
+
+  pub(crate) async fn prepare(&self) -> Result<(), Error> {
+    let (module_specifier, maybe_referrer) = match self.init {
+      LoadInit::Main(ref specifier) => {
+        let spec =
+          self
+            .loader
+            .resolve(specifier, ".", ResolutionKind::MainModule)?;
+        (spec, None)
+      }
+      LoadInit::Side(ref specifier) => {
+        let spec =
+          self
+            .loader
+            .resolve(specifier, ".", ResolutionKind::Import)?;
+        (spec, None)
+      }
+      LoadInit::DynamicImport(ref specifier, ref referrer, _) => {
+        let spec = self.loader.resolve(
+          specifier,
+          referrer,
+          ResolutionKind::DynamicImport,
+        )?;
+        (spec, Some(referrer.to_string()))
+      }
+    };
+
+    self
+      .loader
+      .prepare_load(&module_specifier, maybe_referrer, self.is_dynamic_import())
+      .await
+  }
+
+  fn is_currently_loading_main_module(&self) -> bool {
+    !self.is_dynamic_import()
+      && matches!(self.init, LoadInit::Main(..))
+      && self.state == LoadState::LoadingRoot
+  }
+
+  fn is_dynamic_import(&self) -> bool {
+    matches!(self.init, LoadInit::DynamicImport(..))
+  }
+
+  pub(crate) fn register_and_recurse(
+    &mut self,
+    scope: &mut v8::HandleScope,
+    module_request: &ModuleRequest,
+    module_source: ModuleSource,
+  ) -> Result<(), ModuleError> {
+    let asserted_module_type = module_request.asserted_module_type.clone();
+    if asserted_module_type != module_source.module_type {
+      return Err(ModuleError::Other(generic_error(format!(
+        "Expected a \"{}\" module but loaded a \"{}\" module.",
+        asserted_module_type, module_source.module_type,
+      ))));
+    }
+
+    let module_id = self.module_map_rc.new_module(
+      scope,
+      self.is_currently_loading_main_module(),
+      self.is_dynamic_import(),
+      module_source,
+    )?;
+
+    self.register_and_recurse_inner(module_id, module_request);
+
+    // Update `self.state` however applicable.
+    if self.state == LoadState::LoadingRoot {
+      self.root_module_id = Some(module_id);
+      self.root_asserted_module_type = Some(asserted_module_type);
+      self.state = LoadState::LoadingImports;
+    }
+    if self.pending.is_empty() {
+      self.state = LoadState::Done;
+    }
+
+    Ok(())
+  }
+
+  fn register_and_recurse_inner(
+    &mut self,
+    module_id: usize,
+    module_request: &ModuleRequest,
+  ) {
+    // Recurse the module's imports. There are two cases for each import:
+    // 1. If the module is not in the module map, start a new load for it in
+    //    `self.pending`. The result of that load should eventually be passed to
+    //    this function for recursion.
+    // 2. If the module is already in the module map, queue it up to be
+    //    recursed synchronously here.
+    // This robustly ensures that the whole graph is in the module map before
+    // `LoadState::Done` is set.
+    let mut already_registered = VecDeque::new();
+    already_registered.push_back((module_id, module_request.clone()));
+    self.visited.insert(module_request.clone());
+    while let Some((module_id, module_request)) = already_registered.pop_front()
+    {
+      let referrer = ModuleSpecifier::parse(&module_request.specifier).unwrap();
+      let imports = self
+        .module_map_rc
+        .get_requested_modules(module_id)
+        .unwrap()
+        .clone();
+      for module_request in imports {
+        if !self.visited.contains(&module_request)
+          && !self
+            .visited_as_alias
+            .borrow()
+            .contains(&module_request.specifier)
+        {
+          if let Some(module_id) = self.module_map_rc.get_id(
+            module_request.specifier.as_str(),
+            &module_request.asserted_module_type,
+          ) {
+            already_registered.push_back((module_id, module_request.clone()));
+          } else {
+            let request = module_request.clone();
+            let specifier =
+              ModuleSpecifier::parse(&module_request.specifier).unwrap();
+            let visited_as_alias = self.visited_as_alias.clone();
+            let referrer = referrer.clone();
+            let loader = self.loader.clone();
+            let is_dynamic_import = self.is_dynamic_import();
+            let fut = async move {
+              // `visited_as_alias` unlike `visited` is checked as late as
+              // possible because it can only be populated after completed
+              // loads, meaning a duplicate load future may have already been
+              // dispatched before we know it's a duplicate.
+              if visited_as_alias.borrow().contains(specifier.as_str()) {
+                return Ok(None);
+              }
+              let load_result = loader
+                .load(&specifier, Some(&referrer), is_dynamic_import)
+                .await;
+              if let Ok(source) = &load_result {
+                if let Some(found_specifier) = &source.module_url_found {
+                  visited_as_alias
+                    .borrow_mut()
+                    .insert(found_specifier.as_str().to_string());
+                }
+              }
+              load_result.map(|s| Some((request, s)))
+            };
+            self.pending.push(fut.boxed_local());
+          }
+          self.visited.insert(module_request);
+        }
+      }
+    }
+  }
+}
+
+impl Stream for RecursiveModuleLoad {
+  type Item = Result<(ModuleRequest, ModuleSource), Error>;
+
+  fn poll_next(
+    self: Pin<&mut Self>,
+    cx: &mut Context,
+  ) -> Poll<Option<Self::Item>> {
+    let inner = self.get_mut();
+    // IMPORTANT: Do not borrow `inner.module_map_rc` here. It may not be
+    // available.
+    match inner.state {
+      LoadState::Init => {
+        let module_specifier = match inner.resolve_root() {
+          Ok(url) => url,
+          Err(error) => return Poll::Ready(Some(Err(error))),
+        };
+        let asserted_module_type = match &inner.init {
+          LoadInit::DynamicImport(_, _, module_type) => module_type.clone(),
+          _ => AssertedModuleType::JavaScriptOrWasm,
+        };
+        let module_request = ModuleRequest {
+          specifier: module_specifier.to_string(),
+          asserted_module_type,
+        };
+        let load_fut = if let Some(module_id) = inner.root_module_id {
+          // If the inner future is already in the map, we might be done (assuming there are no pending
+          // loads).
+          inner.register_and_recurse_inner(module_id, &module_request);
+          if inner.pending.is_empty() {
+            inner.state = LoadState::Done;
+          } else {
+            inner.state = LoadState::LoadingImports;
+          }
+          // Internally re-poll using the new state to avoid spinning the event loop again.
+          return Self::poll_next(Pin::new(inner), cx);
+        } else {
+          let maybe_referrer = match inner.init {
+            LoadInit::DynamicImport(_, ref referrer, _) => {
+              resolve_url(referrer).ok()
+            }
+            _ => None,
+          };
+          let loader = inner.loader.clone();
+          let is_dynamic_import = inner.is_dynamic_import();
+          async move {
+            let result = loader
+              .load(
+                &module_specifier,
+                maybe_referrer.as_ref(),
+                is_dynamic_import,
+              )
+              .await;
+            result.map(|s| Some((module_request, s)))
+          }
+          .boxed_local()
+        };
+        inner.pending.push(load_fut);
+        inner.state = LoadState::LoadingRoot;
+        inner.try_poll_next_unpin(cx)
+      }
+      LoadState::LoadingRoot | LoadState::LoadingImports => {
+        match inner.pending.try_poll_next_unpin(cx)? {
+          Poll::Ready(None) => unreachable!(),
+          Poll::Ready(Some(None)) => {
+            if inner.pending.is_empty() {
+              inner.state = LoadState::Done;
+              Poll::Ready(None)
+            } else {
+              Poll::Pending
+            }
+          }
+          Poll::Ready(Some(Some(info))) => Poll::Ready(Some(Ok(info))),
+          Poll::Pending => Poll::Pending,
+        }
+      }
+      LoadState::Done => Poll::Ready(None),
+    }
+  }
+}
diff --git a/core/runtime/jsruntime.rs b/core/runtime/jsruntime.rs
index ed69d18..3f79b6a 100644
--- a/core/runtime/jsruntime.rs
+++ b/core/runtime/jsruntime.rs
@@ -744,10 +744,16 @@ impl JsRuntime {
       .module_loader
       .unwrap_or_else(|| Rc::new(NoopModuleLoader));
 
-    let module_map = Rc::new(ModuleMap::new(loader));
-    if let Some(snapshotted_data) = snapshotted_data {
-      module_map.update_with_snapshotted_data(scope, snapshotted_data);
-    }
+    let module_map = if let Some(snapshotted_data) = snapshotted_data {
+      Rc::new(ModuleMap::new_from_snapshotted_data(
+        loader,
+        scope,
+        snapshotted_data,
+      ))
+    } else {
+      Rc::new(ModuleMap::new(loader))
+    };
+
     context.set_slot(scope, module_map.clone());
 
     let main_realm = {


Test patch:
diff --git a/core/modules/tests.rs b/core/modules/tests.rs
index 3a4a917..f1a0f36 100644
--- a/core/modules/tests.rs
+++ b/core/modules/tests.rs
@@ -3,24 +3,41 @@ use crate::ascii_str;
 use crate::error::exception_to_err_result;
 use crate::modules::loaders::CountingModuleLoader;
 use crate::modules::loaders::ModuleLoadEventCounts;
+use crate::modules::loaders::*;
+use crate::modules::AssertedModuleType;
+use crate::modules::ModuleError;
+use crate::modules::ModuleRequest;
 use crate::resolve_import;
+use crate::resolve_url;
 use crate::runtime::JsRuntime;
 use crate::runtime::JsRuntimeForSnapshot;
+use crate::FastString;
+use crate::ModuleCode;
+use crate::ModuleSource;
+use crate::ModuleSourceFuture;
+use crate::ModuleSpecifier;
+use crate::ModuleType;
+use crate::ResolutionKind;
 use crate::RuntimeOptions;
 use crate::Snapshot;
+use anyhow::Error;
 use deno_ops::op2;
 use futures::future::poll_fn;
 use futures::future::FutureExt;
 use parking_lot::Mutex;
+use std::cell::RefCell;
+use std::collections::HashMap;
 use std::fmt;
 use std::future::Future;
+use std::pin::Pin;
+use std::rc::Rc;
 use std::sync::atomic::AtomicUsize;
 use std::sync::atomic::Ordering;
 use std::sync::Arc;
+use std::task::Context;
+use std::task::Poll;
 use url::Url;
 
-use super::*;
-
 // deno_ops macros generate code assuming deno_core in scope.
 use crate::deno_core;