diff --git a/src/collections/scoped_buffer.rs b/src/collections/scoped_buffer.rs index 4827b030ab01d643a3d8d98e4b2d38894fdbec09..0d5865bd6d7014a443f35c90c53f082ddd838ef8 100644 --- a/src/collections/scoped_buffer.rs +++ b/src/collections/scoped_buffer.rs @@ -26,7 +26,7 @@ pub(crate) struct ScopedSection { } impl ScopedBuffer { - pub(crate) fn new_reserved(capacity: usize) -> Self { + pub(crate) fn with_capacity(capacity: usize) -> Self { Self { inner: Vec::with_capacity(capacity) } } @@ -106,6 +106,16 @@ impl ScopedSection { } } +impl ScopedSection { + pub(crate) fn iter_copied(&self) -> ScopedIter { + return ScopedIter{ + inner: self.inner, + cur_index: self.start_size, + last_index: unsafe{ (*self.inner).len() as u32 }, + } + } +} + impl std::ops::Index for ScopedSection { type Output = T; @@ -122,4 +132,25 @@ impl Drop for ScopedSection { #[cfg(debug_assertions)] debug_assert_eq!(vec.len(), self.cur_size as usize); vec.truncate(self.start_size as usize); } +} + +pub(crate) struct ScopedIter { + inner: *mut Vec, + cur_index: u32, + last_index: u32, +} + +impl Iterator for ScopedIter { + type Item = T; + + fn next(&mut self) -> Option { + if self.cur_index >= self.last_index { + return None; + } + + let vec = unsafe{ &*self.inner }; + let index = self.cur_index as usize; + self.cur_index += 1; + return Some(vec[index]); + } } \ No newline at end of file diff --git a/src/protocol/parser/pass_definitions.rs b/src/protocol/parser/pass_definitions.rs index 0436245808a05644b981900a7705735ba1f7457b..c6b2f994762f6f61637e05f7c3fd29e8198a074b 100644 --- a/src/protocol/parser/pass_definitions.rs +++ b/src/protocol/parser/pass_definitions.rs @@ -31,13 +31,13 @@ impl PassDefinitions { cur_definition: DefinitionId::new_invalid(), type_parser: ParserTypeParser::new(), buffer: String::with_capacity(128), - struct_fields: ScopedBuffer::new_reserved(128), - enum_variants: ScopedBuffer::new_reserved(128), - union_variants: ScopedBuffer::new_reserved(128), - variables: ScopedBuffer::new_reserved(128), - expressions: ScopedBuffer::new_reserved(128), - statements: ScopedBuffer::new_reserved(128), - parser_types: ScopedBuffer::new_reserved(128), + struct_fields: ScopedBuffer::with_capacity(128), + enum_variants: ScopedBuffer::with_capacity(128), + union_variants: ScopedBuffer::with_capacity(128), + variables: ScopedBuffer::with_capacity(128), + expressions: ScopedBuffer::with_capacity(128), + statements: ScopedBuffer::with_capacity(128), + parser_types: ScopedBuffer::with_capacity(128), } } diff --git a/src/protocol/parser/pass_typing.rs b/src/protocol/parser/pass_typing.rs index 8a6f7235acfa8c341c8f5f5dfd2ffc8b34d4146a..0391ec8fa792b4e7dcaba09fe5d36d753a6ec076 100644 --- a/src/protocol/parser/pass_typing.rs +++ b/src/protocol/parser/pass_typing.rs @@ -49,15 +49,14 @@ macro_rules! debug_log { use std::collections::{HashMap, HashSet}; -use crate::collections::DequeSet; +use crate::collections::{ScopedBuffer, DequeSet}; use crate::protocol::ast::*; use crate::protocol::input_source::ParseError; use crate::protocol::parser::ModuleCompilationPhase; use crate::protocol::parser::type_table::*; use crate::protocol::parser::token_parsing::*; use super::visitor::{ - STMT_BUFFER_INIT_CAPACITY, - EXPR_BUFFER_INIT_CAPACITY, + BUFFER_INIT_CAPACITY, Ctx, Visitor, VisitorResult @@ -858,11 +857,10 @@ pub(crate) struct PassTyping { reserved_idx: i32, definition_type: DefinitionType, poly_vars: Vec, - // Buffers for iteration over substatements and subexpressions - stmt_buffer: Vec, - expr_buffer: Vec, - + var_buffer: ScopedBuffer, + expr_buffer: ScopedBuffer, + stmt_buffer: ScopedBuffer, // Mapping from parser type to inferred type. We attempt to continue to // specify these types until we're stuck or we've fully determined the type. var_types: HashMap, // types of variables @@ -922,8 +920,9 @@ impl PassTyping { reserved_idx: -1, definition_type: DefinitionType::Function(FunctionDefinitionId::new_invalid()), poly_vars: Vec::new(), - stmt_buffer: Vec::with_capacity(STMT_BUFFER_INIT_CAPACITY), - expr_buffer: Vec::with_capacity(EXPR_BUFFER_INIT_CAPACITY), + var_buffer: ScopedBuffer::with_capacity(BUFFER_INIT_CAPACITY), + expr_buffer: ScopedBuffer::with_capacity(BUFFER_INIT_CAPACITY), + stmt_buffer: ScopedBuffer::with_capacity(BUFFER_INIT_CAPACITY), var_types: HashMap::new(), expr_types: Vec::new(), extra_data: Vec::new(), @@ -997,8 +996,6 @@ impl PassTyping { self.reserved_idx = -1; self.definition_type = DefinitionType::Function(FunctionDefinitionId::new_invalid()); self.poly_vars.clear(); - self.stmt_buffer.clear(); - self.expr_buffer.clear(); self.var_types.clear(); self.expr_types.clear(); self.extra_data.clear(); @@ -1024,12 +1021,14 @@ impl Visitor for PassTyping { self.expr_types.resize(comp_def.num_expressions_in_body as usize, Default::default()); // Visit parameters - for param_id in comp_def.parameters.clone() { + let section = self.var_buffer.start_section_initialized(comp_def.parameters.as_slice()); + for param_id in section.iter_copied() { let param = &ctx.heap[param_id]; let var_type = self.determine_inference_type_from_parser_type_elements(¶m.parser_type.elements, true); debug_assert!(var_type.is_done, "expected component arguments to be concrete types"); self.var_types.insert(param_id, VarData::new_local(var_type)); } + section.forget(); // Visit the body and all of its expressions let body_stmt_id = ctx.heap[id].body; @@ -1062,12 +1061,14 @@ impl Visitor for PassTyping { self.expr_types.resize(func_def.num_expressions_in_body as usize, Default::default()); // Visit parameters - for param_id in func_def.parameters.clone() { + let section = self.var_buffer.start_section_initialized(func_def.parameters.as_slice()); + for param_id in section.iter_copied() { let param = &ctx.heap[param_id]; let var_type = self.determine_inference_type_from_parser_type_elements(¶m.parser_type.elements, true); debug_assert!(var_type.is_done, "expected function arguments to be concrete types"); self.var_types.insert(param_id, VarData::new_local(var_type)); } + section.forget(); // Visit all of the expressions within the body let body_stmt_id = ctx.heap[id].body; @@ -1080,9 +1081,11 @@ impl Visitor for PassTyping { // Transfer statements for traversal let block = &ctx.heap[id]; - for stmt_id in block.statements.clone() { + let section = self.stmt_buffer.start_section_initialized(block.statements.as_slice()); + for stmt_id in section.iter_copied() { self.visit_stmt(ctx, stmt_id)?; } + section.forget(); Ok(()) } @@ -1312,17 +1315,16 @@ impl Visitor for PassTyping { // No subexpressions }, Literal::Struct(literal) => { - // TODO: @performance - let expr_ids: Vec<_> = literal.fields - .iter() - .map(|f| f.value) - .collect(); - + let mut expr_ids = self.expr_buffer.start_section(); + for field in &literal.fields { + expr_ids.push(field.value); + } self.insert_initial_struct_polymorph_data(ctx, id); - for expr_id in expr_ids { + for expr_id in expr_ids.iter_copied() { self.visit_expr(ctx, expr_id)?; } + expr_ids.forget(); }, Literal::Enum(_) => { // Enumerations do not carry any subexpressions, but may still @@ -1333,20 +1335,20 @@ impl Visitor for PassTyping { }, Literal::Union(literal) => { // May carry subexpressions and polymorphic arguments - // TODO: @performance - let expr_ids = literal.values.clone(); + let expr_ids = self.expr_buffer.start_section_initialized(literal.values.as_slice()); self.insert_initial_union_polymorph_data(ctx, id); - for expr_id in expr_ids { + for expr_id in expr_ids.iter_copied() { self.visit_expr(ctx, expr_id)?; } + expr_ids.forget(); }, Literal::Array(expressions) | Literal::Tuple(expressions) => { - // TODO: @performance - let expr_ids = expressions.clone(); - for expr_id in expr_ids { + let expr_ids = self.expr_buffer.start_section_initialized(expressions.as_slice()); + for expr_id in expr_ids.iter_copied() { self.visit_expr(ctx, expr_id)?; } + expr_ids.forget(); } } @@ -1377,9 +1379,11 @@ impl Visitor for PassTyping { self.expr_types[call_expr.unique_id_in_definition as usize].field_or_monomorph_idx = 0; // Visit all arguments - for arg_expr_id in call_expr.arguments.clone() { // TODO: @Performance + let expr_ids = self.expr_buffer.start_section_initialized(call_expr.arguments.as_slice()); + for arg_expr_id in expr_ids.iter_copied() { self.visit_expr(ctx, arg_expr_id)?; } + expr_ids.forget(); self.progress_call_expr(ctx, id) } @@ -1622,7 +1626,7 @@ impl PassTyping { } fn progress_expr(&mut self, ctx: &mut Ctx, idx: i32) -> Result<(), ParseError> { - let id = self.expr_types[idx as usize].expr_id; // TODO: @Temp + let id = self.expr_types[idx as usize].expr_id; match &ctx.heap[id] { Expression::Assignment(expr) => { let id = expr.this; @@ -2152,7 +2156,7 @@ impl PassTyping { // information is inserted into `extra_data`. Check to see if we can // do some mutual inference. let poly_data = &mut self.extra_data[extra_idx as usize]; - let mut poly_progress = HashSet::new(); + let mut poly_progress = HashSet::new(); // TODO: @Performance // Apply to struct's type let signature_type: *mut _ = &mut poly_data.embedded[0]; @@ -2518,6 +2522,7 @@ impl PassTyping { progress_expr }, Literal::Array(data) => { + // TODO: Continue here with performance improvements by reducing allocations let expr_elements = data.clone(); // TODO: @performance debug_log!("Array expr ({} elements): {}", expr_elements.len(), upcast_id.index); debug_log!(" * Before:"); diff --git a/src/protocol/parser/pass_validation_linking.rs b/src/protocol/parser/pass_validation_linking.rs index a2c27b912c13e69b7ecfaffe674d10d8cc5ea4db..3753d46b648257fef64d7a2ee40edc686c55b948 100644 --- a/src/protocol/parser/pass_validation_linking.rs +++ b/src/protocol/parser/pass_validation_linking.rs @@ -42,8 +42,7 @@ use crate::protocol::parser::symbol_table::*; use crate::protocol::parser::type_table::*; use super::visitor::{ - STMT_BUFFER_INIT_CAPACITY, - EXPR_BUFFER_INIT_CAPACITY, + BUFFER_INIT_CAPACITY, Ctx, Visitor, VisitorResult @@ -126,10 +125,10 @@ impl PassValidationLinking { must_be_assignable: None, relative_pos_in_block: 0, next_expr_index: 0, - variable_buffer: ScopedBuffer::new_reserved(128), - definition_buffer: ScopedBuffer::new_reserved(128), - statement_buffer: ScopedBuffer::new_reserved(STMT_BUFFER_INIT_CAPACITY), - expression_buffer: ScopedBuffer::new_reserved(EXPR_BUFFER_INIT_CAPACITY), + variable_buffer: ScopedBuffer::with_capacity(128), + definition_buffer: ScopedBuffer::with_capacity(128), + statement_buffer: ScopedBuffer::with_capacity(BUFFER_INIT_CAPACITY), + expression_buffer: ScopedBuffer::with_capacity(BUFFER_INIT_CAPACITY), } } diff --git a/src/protocol/parser/visitor.rs b/src/protocol/parser/visitor.rs index d4be7a7575dfc5c54745fa89036dfc7e6e30dde7..edd9bf5e3989728d794ca63b514600e7b50953f8 100644 --- a/src/protocol/parser/visitor.rs +++ b/src/protocol/parser/visitor.rs @@ -6,12 +6,8 @@ use crate::protocol::symbol_table::{SymbolTable}; type Unit = (); pub(crate) type VisitorResult = Result; -/// Globally configured vector capacity for statement buffers in visitor -/// implementations -pub(crate) const STMT_BUFFER_INIT_CAPACITY: usize = 256; -/// Globally configured vector capacity for expression buffers in visitor -/// implementations -pub(crate) const EXPR_BUFFER_INIT_CAPACITY: usize = 256; +/// Globally configured vector capacity for buffers in visitor implementations +pub(crate) const BUFFER_INIT_CAPACITY: usize = 256; /// General context structure that is used while traversing the AST. pub(crate) struct Ctx<'p> {