Skip to content

Commit

Permalink
Rework parsed module storage and ordering algorithm.
Browse files Browse the repository at this point in the history
  • Loading branch information
tritao committed Sep 22, 2024
1 parent 5101f16 commit dca621f
Show file tree
Hide file tree
Showing 22 changed files with 585 additions and 155 deletions.
131 changes: 131 additions & 0 deletions sway-core/src/concurrent_slab_mut.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
use std::{
fmt,
sync::{Arc, RwLock},
};

#[derive(Debug, Clone)]
pub struct Inner<T> {
pub items: Vec<Option<Arc<RwLock<T>>>>,
pub free_list: Vec<usize>,
}

impl<T> Default for Inner<T> {
fn default() -> Self {
Self {
items: Default::default(),
free_list: Default::default(),
}
}
}

#[derive(Debug)]
pub(crate) struct ConcurrentSlabMut<T> {
pub inner: RwLock<Inner<T>>,
}

impl<T> Clone for ConcurrentSlabMut<T>
where
T: Clone,
{
fn clone(&self) -> Self {
let inner = self.inner.read().unwrap();
Self {
inner: RwLock::new(inner.clone()),
}
}
}

impl<T> Default for ConcurrentSlabMut<T> {
fn default() -> Self {
Self {
inner: Default::default(),
}
}
}

pub struct ListDisplay<I> {
pub list: I,
}

impl<I: IntoIterator + Clone> fmt::Display for ListDisplay<I>
where
I::Item: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let fmt_elems = self
.list
.clone()
.into_iter()
.enumerate()
.map(|(i, value)| format!("{i:<10}\t->\t{value}"))
.collect::<Vec<_>>();
write!(f, "{}", fmt_elems.join("\n"))
}
}

impl<T> ConcurrentSlabMut<T>
where
T: Clone,
{
#[allow(dead_code)]
pub fn len(&self) -> usize {
let inner = self.inner.read().unwrap();
inner.items.len()
}

#[allow(dead_code)]
pub fn values(&self) -> Vec<Arc<RwLock<T>>> {
let inner = self.inner.read().unwrap();
inner.items.iter().filter_map(|x| x.clone()).collect()
}

pub fn insert(&self, value: T) -> usize {
self.insert_arc(Arc::new(RwLock::new(value)))
}

pub fn insert_arc(&self, value: Arc<RwLock<T>>) -> usize {
let mut inner = self.inner.write().unwrap();

if let Some(free) = inner.free_list.pop() {
assert!(inner.items[free].is_none());
inner.items[free] = Some(value);
free
} else {
inner.items.push(Some(value));
inner.items.len() - 1
}
}

pub fn get(&self, index: usize) -> Arc<RwLock<T>> {
let inner = self.inner.read().unwrap();
inner.items[index]
.as_ref()
.expect("invalid slab index for ConcurrentSlab::get")
.clone()
}

#[allow(dead_code)]
pub fn retain(&self, predicate: impl Fn(&usize, &mut Arc<RwLock<T>>) -> bool) {
let mut inner = self.inner.write().unwrap();

let Inner { items, free_list } = &mut *inner;
for (idx, item) in items.iter_mut().enumerate() {
if let Some(arc) = item {
if !predicate(&idx, arc) {
free_list.push(idx);
item.take();
}
}
}
}

#[allow(dead_code)]
pub fn clear(&self) {
let mut inner = self.inner.write().unwrap();
inner.items.clear();
inner.items.shrink_to(0);

inner.free_list.clear();
inner.free_list.shrink_to(0);
}
}
8 changes: 8 additions & 0 deletions sway-core/src/engine_threading.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
decl_engine::{parsed_engine::ParsedDeclEngine, DeclEngine},
language::parsed::ParsedModuleEngine,
query_engine::QueryEngine,
type_system::TypeEngine,
};
Expand All @@ -15,6 +16,7 @@ pub struct Engines {
type_engine: TypeEngine,
decl_engine: DeclEngine,
parsed_decl_engine: ParsedDeclEngine,
parsed_module_engine: ParsedModuleEngine,
query_engine: QueryEngine,
source_engine: SourceEngine,
}
Expand All @@ -32,6 +34,10 @@ impl Engines {
&self.parsed_decl_engine
}

pub fn pme(&self) -> &ParsedModuleEngine {
&self.parsed_module_engine
}

pub fn qe(&self) -> &QueryEngine {
&self.query_engine
}
Expand All @@ -46,6 +52,7 @@ impl Engines {
self.type_engine.clear_program(program_id);
self.decl_engine.clear_program(program_id);
self.parsed_decl_engine.clear_program(program_id);
// self.parsed_module_engine.clear_program(program_id);
}

/// Removes all data associated with `source_id` from the declaration and type engines.
Expand All @@ -54,6 +61,7 @@ impl Engines {
self.type_engine.clear_module(source_id);
self.decl_engine.clear_module(source_id);
self.parsed_decl_engine.clear_module(source_id);
// self.parsed_module_engine.clear_module(source_id);
}

/// Helps out some `thing: T` by adding `self` as context.
Expand Down
12 changes: 10 additions & 2 deletions sway-core/src/language/module.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
use sway_types::Ident;

use super::parsed::ParseModuleId;

/// The name used within a module to refer to one of its submodules.
///
/// If an alias was given to the `mod`, this will be the alias. If not, this is the submodule's
/// library name.
pub type ModName = Ident;

pub type ModPath = Vec<ModName>;

pub trait HasModuleId
{
/// Returns the associated module id.
fn module_id(&self) -> ParseModuleId;
}

pub trait HasModule<T>
where
T: HasSubmodules<Self>,
Self: Sized,
{
/// Returns the module of this submodule.
Expand All @@ -17,7 +26,6 @@ where

pub trait HasSubmodules<E>
where
E: HasModule<Self>,
Self: Sized,
{
/// Returns the submodules of this module.
Expand Down
2 changes: 2 additions & 0 deletions sway-core/src/language/parsed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod declaration;
mod expression;
mod include_statement;
mod module;
mod parsed_module_engine;
mod program;
mod use_statement;

Expand All @@ -12,6 +13,7 @@ pub use declaration::*;
pub use expression::*;
pub use include_statement::IncludeStatement;
pub use module::{ModuleEvaluationOrder, ParseModule, ParseSubmodule};
pub use parsed_module_engine::*;
pub use program::{ParseProgram, TreeType};
use sway_error::handler::ErrorEmitted;
use sway_types::span::Span;
Expand Down
62 changes: 55 additions & 7 deletions sway-core/src/language/parsed/module.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
use crate::{
language::{HasModule, HasSubmodules, ModName, Visibility},
transform,
language::{HasModule, HasModuleId, HasSubmodules, ModName, Visibility},
namespace::ModulePath,
transform, Engines,
};

use super::ParseTree;
use super::{ParseModuleId, ParseTree};
use sway_error::{
error::CompileError,
handler::{ErrorEmitted, Handler},
};
use sway_types::Span;

pub type ModuleHash = u64;
pub type ModuleEvaluationOrder = Vec<ModName>;
pub type ModuleEvaluationOrder = Vec<ParseModuleId>;

/// A module and its submodules in the form of a tree.
#[derive(Debug, Clone)]
pub struct ParseModule {
pub id: ParseModuleId,
/// Parent module id or `None` if its a root module.
pub parent: Option<ParseModuleId>,
/// The content of this module in the form of a `ParseTree`.
pub tree: ParseTree,
/// Submodules introduced within this module using the `dep` syntax in order of declaration.
Expand All @@ -25,20 +33,60 @@ pub struct ParseModule {
pub span: Span,
/// an hash used for caching the module
pub hash: ModuleHash,
pub name: Option<String>,
}

impl ParseModule {
/// Lookup the submodule at the given path.
pub fn lookup_submodule(
&self,
handler: &Handler,
engines: &Engines,
path: &ModulePath,
) -> Result<ParseModuleId, ErrorEmitted> {
let pme = engines.pme();
let mut module_id = self.id;
for ident in path.iter() {
let module_arc = pme.get(&module_id);
let module = module_arc.read().unwrap();
match module.submodules.iter().find(|(name, _)| name == ident) {
Some((_name, submod)) => module_id = submod.module,
None => {
return Err(handler.emit_err(CompileError::Internal(
"Cannot find submodule",
Span::dummy(),
)))
}
}
}
Ok(module_id)
}
}

impl HasModuleId for ParseModule {
fn module_id(&self) -> ParseModuleId {
self.id
}
}

/// A library module that was declared as a `mod` of another module.
///
/// Only submodules are guaranteed to be a `library`.
#[derive(Debug, Clone)]
pub struct ParseSubmodule {
pub module: ParseModule,
pub module: ParseModuleId,
pub mod_name_span: Span,
pub visibility: Visibility,
}

impl HasModule<ParseModule> for ParseSubmodule {
fn module(&self) -> &ParseModule {
impl HasModuleId for ParseSubmodule {
fn module_id(&self) -> ParseModuleId {
self.module
}
}

impl HasModule<ParseModuleId> for ParseSubmodule {
fn module(&self) -> &ParseModuleId {
&self.module
}
}
Expand Down
81 changes: 81 additions & 0 deletions sway-core/src/language/parsed/parsed_module_engine.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use std::sync::{Arc, RwLock};

use crate::{concurrent_slab_mut::ConcurrentSlabMut, engine_threading::DebugWithEngines};

use super::ParseModule;

/// A identifier to uniquely refer to our parsed modules.
#[derive(Default, PartialEq, Eq, Hash, Clone, Copy, Ord, PartialOrd, Debug)]
pub struct ParseModuleId(usize);

impl ParseModuleId {
pub fn new(index: usize) -> Self {
ParseModuleId(index)
}

/// Returns the index that identifies the type.
pub fn index(&self) -> usize {
self.0
}

pub(crate) fn get(&self, engines: &crate::Engines) -> Arc<RwLock<ParseModule>> {
engines.pme().get(self)
}

pub fn read<R>(&self, engines: &crate::Engines, f: impl Fn(&ParseModule) -> R) -> R {
let value = self.get(engines);
let value = value.read().unwrap();
f(&value)
}

pub fn write<R>(
&self,
engines: &crate::Engines,
mut f: impl FnMut(&mut ParseModule) -> R,
) -> R {
let value = self.get(engines);
let mut value = value.write().unwrap();
f(&mut value)
}
}

impl DebugWithEngines for ParseModuleId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, engines: &crate::Engines) -> std::fmt::Result {
let name = self.read(engines, |m| m.name.clone());
write!(f, "{:?}", name)
}
}

/// The Parsed Module Engine manages a relationship between module ids and their corresponding
/// parsed module structures.
#[derive(Debug, Default, Clone)]
pub struct ParsedModuleEngine {
slab: ConcurrentSlabMut<ParseModule>,
}

impl ParsedModuleEngine {
/// This function provides the namespace module corresponding to a specified module ID.
pub fn get(&self, module_id: &ParseModuleId) -> Arc<RwLock<ParseModule>> {
self.slab.get(module_id.index())
}

pub fn read<R>(&self, module_id: &ParseModuleId, f: impl Fn(&ParseModule) -> R) -> R {
let value = self.slab.get(module_id.index());
let value = value.read().unwrap();
f(&value)
}

pub fn write<R>(&self, module_id: &ParseModuleId, f: impl Fn(&mut ParseModule) -> R) -> R {
let value = self.slab.get(module_id.index());
let mut value = value.write().unwrap();
f(&mut value)
}

pub fn insert(&self, value: ParseModule) -> ParseModuleId {
let id = ParseModuleId(self.slab.insert(value));
self.write(&id, |m| {
m.id = id;
});
id
}
}
Loading

0 comments on commit dca621f

Please sign in to comment.