From 192a4f66fe6c647d426576758f21db3a4d178e6c Mon Sep 17 00:00:00 2001 From: Lukas Tenbrink Date: Tue, 16 Jul 2024 18:58:31 +0200 Subject: [PATCH] Attach a compile server to the runtime. Move related objects there. The server also owns a Simplify (and Refactor), which is used to avoid compiling the same thing twice if subsequent compiles are called. Instead of compiling functions statically, compile them through the server in all places. --- src/interpreter.rs | 4 +- src/interpreter/builtins/vm.rs | 13 +- src/interpreter/compile.rs | 3 +- src/interpreter/compile/compile_server.rs | 99 ++++++++++++ src/interpreter/compile/function_compiler.rs | 147 +----------------- .../compile/function_descriptor_compiler.rs | 81 ++++++++++ src/interpreter/data_layout.rs | 5 +- src/interpreter/run.rs | 5 +- src/interpreter/runtime.rs | 31 +--- src/interpreter/tests.rs | 10 +- src/interpreter/vm.rs | 18 ++- src/refactor.rs | 10 +- src/refactor/simplify.rs | 29 +--- src/transpiler.rs | 22 ++- 14 files changed, 251 insertions(+), 226 deletions(-) create mode 100644 src/interpreter/compile/function_descriptor_compiler.rs diff --git a/src/interpreter.rs b/src/interpreter.rs index e0afdb3..42e7a0d 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -6,6 +6,6 @@ pub mod opcode; pub mod disassembler; pub mod data; pub mod runtime; +pub mod data_layout; +pub mod compile; mod tests; -mod data_layout; -mod compile; diff --git a/src/interpreter/builtins/vm.rs b/src/interpreter/builtins/vm.rs index ce9a340..52ea664 100644 --- a/src/interpreter/builtins/vm.rs +++ b/src/interpreter/builtins/vm.rs @@ -1,5 +1,6 @@ -use std::rc::Rc; use std::path::PathBuf; +use std::rc::Rc; + use crate::error::RResult; use crate::interpreter::compile::function_compiler::InlineFunction; use crate::interpreter::opcode::{OpCode, Primitive}; @@ -18,7 +19,7 @@ pub fn load(runtime: &mut Runtime) -> RResult<()> { runtime.get_or_load_module(&module_name("core"))?; for function in runtime.source.module_by_name[&module_name("core.debug")].explicit_functions(&runtime.source) { - runtime.function_inlines.insert(Rc::clone(function), match function.declared_representation.name.as_str() { + runtime.compile_server.function_inlines.insert(Rc::clone(function), match function.declared_representation.name.as_str() { "_write_line" => inline_fn_push(OpCode::PRINT), "_exit_with_error" => inline_fn_push(OpCode::PANIC), _ => continue, @@ -26,14 +27,14 @@ pub fn load(runtime: &mut Runtime) -> RResult<()> { } for function in runtime.source.module_by_name[&module_name("core.transpilation")].explicit_functions(&runtime.source) { - runtime.function_inlines.insert(Rc::clone(function), match function.declared_representation.name.as_str() { + runtime.compile_server.function_inlines.insert(Rc::clone(function), match function.declared_representation.name.as_str() { "add" => inline_fn_push(OpCode::TRANSPILE_ADD), _ => continue, }); } for function in runtime.source.module_by_name[&module_name("core.bool")].explicit_functions(&runtime.source) { - runtime.function_inlines.insert(Rc::clone(function), match function.declared_representation.name.as_str() { + runtime.compile_server.function_inlines.insert(Rc::clone(function), match function.declared_representation.name.as_str() { "true" => inline_fn_push_with_u8(OpCode::LOAD8, true as u8), "false" => inline_fn_push_with_u8(OpCode::LOAD8, false as u8), _ => continue, @@ -41,7 +42,7 @@ pub fn load(runtime: &mut Runtime) -> RResult<()> { } for function in runtime.source.module_by_name[&module_name("core.strings")].explicit_functions(&runtime.source) { - runtime.function_inlines.insert(Rc::clone(function), match function.declared_representation.name.as_str() { + runtime.compile_server.function_inlines.insert(Rc::clone(function), match function.declared_representation.name.as_str() { "add" => inline_fn_push(OpCode::ADD_STRING), _ => continue, }); @@ -56,7 +57,7 @@ pub fn load(runtime: &mut Runtime) -> RResult<()> { continue; }; - runtime.function_inlines.insert(Rc::clone(function), match descriptor { + runtime.compile_server.function_inlines.insert(Rc::clone(function), match descriptor { FunctionLogicDescriptor::Stub => todo!(), FunctionLogicDescriptor::Clone(type_) => { if type_ == &TypeProto::unit_struct(&runtime.traits.as_ref().unwrap().String) { diff --git a/src/interpreter/compile.rs b/src/interpreter/compile.rs index 6765072..bd7e147 100644 --- a/src/interpreter/compile.rs +++ b/src/interpreter/compile.rs @@ -1,2 +1,3 @@ pub mod function_compiler; -mod compile_server; \ No newline at end of file +pub mod compile_server; +pub mod function_descriptor_compiler; diff --git a/src/interpreter/compile/compile_server.rs b/src/interpreter/compile/compile_server.rs index 7363923..774d068 100644 --- a/src/interpreter/compile/compile_server.rs +++ b/src/interpreter/compile/compile_server.rs @@ -1,3 +1,102 @@ +use std::collections::HashMap; +use std::rc::Rc; + +use uuid::Uuid; + +use crate::error::{RResult, RuntimeError}; +use crate::interpreter::chunks::Chunk; +use crate::interpreter::compile::function_compiler::{compile_function, InlineFunction}; +use crate::interpreter::compile::function_descriptor_compiler::compile_descriptor; +use crate::interpreter::data_layout::{create_data_layout, DataLayout}; +use crate::program::functions::{FunctionHead, FunctionLogic}; +use crate::program::traits::StructInfo; +use crate::refactor::Refactor; +use crate::refactor::simplify::Simplify; +use crate::source::Source; + pub struct CompileServer { + pub simplify: Simplify, + + // These are optimized for running and may not reflect the source code itself. + // They are also only loaded on demand. + pub function_evaluators: HashMap>, + // TODO We'll need these only in the future when we compile functions to constants. + // pub global_assignments: HashMap, + pub function_inlines: HashMap, InlineFunction>, + pub data_layouts: HashMap, Rc>, +} + +impl CompileServer { + pub fn new() -> CompileServer { + CompileServer { + simplify: Simplify { + refactor: Refactor::new(), + inline: true, + trim_locals: true, + monomorphize: true, + }, + function_evaluators: Default::default(), + function_inlines: Default::default(), + data_layouts: Default::default(), + } + } + + pub fn compile_deep(&mut self, source: &Source, function: &Rc) -> RResult> { + let FunctionLogic::Implementation(implementation) = source.fn_logic[function].clone() else { + return Err(RuntimeError::error("main! function was somehow internal.").to_array()); + }; + + self.simplify.refactor.add(implementation); + + self.simplify.run(source); + + let needed_functions = self.simplify.refactor.gather_needed_functions(source); + let fn_logic = self.simplify.refactor.fn_logic.clone(); + + let mut errors = vec![]; + + for function in needed_functions { + match &fn_logic[&function] { + FunctionLogic::Descriptor(d) => { + if self.function_inlines.contains_key(&function) || self.function_evaluators.contains_key(&function.function_id) { + continue + } + + compile_descriptor(&function, d, self); + } + FunctionLogic::Implementation(implementation) => { + match compile_function(self, implementation) { + Ok(compiled) => drop(self.function_evaluators.insert(function.function_id, compiled)), + Err(err) => errors.extend(err), + }; + } + } + } + + let FunctionLogic::Implementation(implementation) = &fn_logic[function] else { + errors.push(RuntimeError::error("main! function was somehow internal after refactor.")); + return Err(errors); + }; + + match compile_function(self, implementation) { + Ok(compiled) => { + if !errors.is_empty() { Err(errors) } + else { Ok(compiled) } + }, + Err(err) => { + errors.extend(err); + Err(errors) + }, + } + } + + pub fn get_data_layout(&mut self, struct_info: &Rc) -> Rc { + if let Some(layout) = self.data_layouts.get(struct_info) { + return Rc::clone(layout) + } + let layout = create_data_layout(Rc::clone(struct_info)); + self.data_layouts.insert(Rc::clone(struct_info), Rc::clone(&layout)); + layout + } } diff --git a/src/interpreter/compile/function_compiler.rs b/src/interpreter/compile/function_compiler.rs index db7047f..f07ca5d 100644 --- a/src/interpreter/compile/function_compiler.rs +++ b/src/interpreter/compile/function_compiler.rs @@ -1,85 +1,29 @@ -use std::collections::hash_map::Entry; -use std::collections::HashMap; use std::mem::transmute; use std::rc::Rc; use itertools::Itertools; -use crate::error::{RResult, RuntimeError}; +use crate::error::RResult; use crate::interpreter::chunks::Chunk; -use crate::interpreter::data::{string_to_ptr, uuid_to_ptr, Value}; +use crate::interpreter::compile::compile_server::CompileServer; +use crate::interpreter::data::{string_to_ptr, Value}; use crate::interpreter::opcode::OpCode; -use crate::interpreter::runtime::Runtime; use crate::program::allocation::ObjectReference; use crate::program::expression_tree::{ExpressionID, ExpressionOperation}; -use crate::program::functions::{FunctionHead, FunctionImplementation, FunctionLogic, FunctionLogicDescriptor}; -use crate::refactor::Refactor; -use crate::refactor::simplify::Simplify; -use crate::transpiler; +use crate::program::functions::FunctionImplementation; pub type InlineFunction = Rc RResult<()>>; pub struct FunctionCompiler<'a> { - pub runtime: &'a Runtime, + pub compile_server: &'a CompileServer, pub implementation: &'a FunctionImplementation, pub chunk: Chunk, pub alloced_locals: Vec>, } -pub fn compile_deep(runtime: &mut Runtime, function: &Rc) -> RResult> { - let FunctionLogic::Implementation(implementation) = runtime.source.fn_logic[function].clone() else { - return Err(RuntimeError::error("main! function was somehow internal.").to_array()); - }; - - let mut refactor = Refactor::new(); - refactor.add(implementation); - - let mut simplify = Simplify::new(&mut refactor, &transpiler::Config::default()); - simplify.run(runtime); - - let needed_functions = refactor.gather_needed_functions(runtime); - let fn_logic = refactor.fn_logic; - - let mut errors = vec![]; - - for function in needed_functions { - match &fn_logic[&function] { - FunctionLogic::Descriptor(d) => { - if runtime.function_inlines.contains_key(&function) || runtime.function_evaluators.contains_key(&function.function_id) { - continue - } - - compile_descriptor(&function, d, runtime); - } - FunctionLogic::Implementation(implementation) => { - match compile_function(runtime, implementation) { - Ok(compiled) => drop(runtime.function_evaluators.insert(function.function_id, compiled)), - Err(err) => errors.extend(err), - }; - } - } - } - - let FunctionLogic::Implementation(implementation) = &fn_logic[function] else { - errors.push(RuntimeError::error("main! function was somehow internal after refactor.")); - return Err(errors); - }; - - match compile_function(runtime, implementation) { - Ok(compiled) => { - if !errors.is_empty() { Err(errors) } - else { Ok(compiled) } - }, - Err(err) => { - errors.extend(err); - Err(errors) - }, - } -} - -fn compile_function(runtime: &mut Runtime, implementation: &FunctionImplementation) -> RResult> { +pub fn compile_function(compile_server: &CompileServer, implementation: &FunctionImplementation) -> RResult> { let mut compiler = FunctionCompiler { - runtime, + compile_server, implementation, chunk: Chunk::new(), alloced_locals: vec![], @@ -162,7 +106,7 @@ impl FunctionCompiler<'_> { self.compile_return(); }, ExpressionOperation::FunctionCall(function_binding) => { - if let Some(inline_fn) = self.runtime.function_inlines.get(&function_binding.function) { + if let Some(inline_fn) = self.compile_server.function_inlines.get(&function_binding.function) { inline_fn(self, expression)?; } else { @@ -221,78 +165,3 @@ impl FunctionCompiler<'_> { i32::try_from(self.alloced_locals.iter().position(|l| l == object).unwrap()).unwrap() - i32::try_from(self.implementation.head.interface.parameters.len()).unwrap() } } - -pub fn compile_descriptor(function: &Rc, descriptor: &FunctionLogicDescriptor, runtime: &mut Runtime) { - match descriptor { - FunctionLogicDescriptor::Stub => todo!("{:?}", function), - FunctionLogicDescriptor::Clone(_) => todo!("{:?}", function), - FunctionLogicDescriptor::TraitProvider(trait_) => { - let uuid = trait_.id; - runtime.function_inlines.insert(Rc::clone(function), Rc::new(move |compiler, expression| { - unsafe { compiler.chunk.constants.push(Value { ptr: uuid_to_ptr(uuid) }); } - compiler.chunk.push_with_u32(OpCode::LOAD_CONSTANT_32, u32::try_from(compiler.chunk.constants.len() - 1).unwrap()); - Ok(()) - })); - }, - FunctionLogicDescriptor::FunctionProvider(f) => { - let uuid = f.function_id; - runtime.function_inlines.insert(Rc::clone(function), Rc::new(move |compiler, expression| { - unsafe { compiler.chunk.constants.push(Value { ptr: uuid_to_ptr(uuid) }); } - compiler.chunk.push_with_u32(OpCode::LOAD_CONSTANT_32, u32::try_from(compiler.chunk.constants.len() - 1).unwrap()); - Ok(()) - })); - } - FunctionLogicDescriptor::PrimitiveOperation { .. } => todo!("{:?}", descriptor), - FunctionLogicDescriptor::Constructor(struct_info) => { - let data_layout = runtime.get_data_layout(struct_info); - - runtime.function_inlines.insert(Rc::clone(function), Rc::new(move |compiler, expression| { - let arguments = &compiler.implementation.expression_tree.children[&expression]; - assert_eq!(arguments.len(), data_layout.fields.len() + 1); - - compiler.chunk.push_with_u32(OpCode::ALLOC_32, u32::try_from(data_layout.fields.len()).unwrap()); - for (idx, arg) in arguments.iter().skip(1).enumerate() { - // If needed, duplicate the object pointer. - if idx < arguments.len() - 1 { - compiler.chunk.push(OpCode::DUP64); - } - - // Evaluate the field at the given index. - compiler.compile_expression(arg)?; - compiler.chunk.push_with_u32(OpCode::SET_MEMBER_32, u32::try_from(idx).unwrap()); - } - - Ok(()) - })); - }, - FunctionLogicDescriptor::GetMemberField(struct_info, ref_) => { - let data_layout = runtime.get_data_layout(struct_info); - let slot_index = data_layout.fields.iter().position(|r| r == ref_).unwrap(); - - runtime.function_inlines.insert(Rc::clone(function), Rc::new(move |compiler, expression| { - let arguments = &compiler.implementation.expression_tree.children[&expression]; - - compiler.compile_expression(&arguments[0])?; - - compiler.chunk.push_with_u32(OpCode::GET_MEMBER_32, u32::try_from(slot_index).unwrap()); - - Ok(()) - })); - }, - FunctionLogicDescriptor::SetMemberField(struct_info, ref_) => { - let data_layout = runtime.get_data_layout(struct_info); - let slot_index = data_layout.fields.iter().position(|r| r == ref_).unwrap(); - - runtime.function_inlines.insert(Rc::clone(function), Rc::new(move |compiler, expression| { - let arguments = &compiler.implementation.expression_tree.children[&expression]; - - compiler.compile_expression(&arguments[0])?; - compiler.compile_expression(&arguments[1])?; - - compiler.chunk.push_with_u32(OpCode::SET_MEMBER_32, u32::try_from(slot_index).unwrap()); - - Ok(()) - })); - }, - } -} diff --git a/src/interpreter/compile/function_descriptor_compiler.rs b/src/interpreter/compile/function_descriptor_compiler.rs new file mode 100644 index 0000000..e87a6da --- /dev/null +++ b/src/interpreter/compile/function_descriptor_compiler.rs @@ -0,0 +1,81 @@ +use std::rc::Rc; + +use crate::interpreter::compile::compile_server::CompileServer; +use crate::interpreter::data::{uuid_to_ptr, Value}; +use crate::interpreter::opcode::OpCode; +use crate::program::functions::{FunctionHead, FunctionLogicDescriptor}; + +pub fn compile_descriptor(function: &Rc, descriptor: &FunctionLogicDescriptor, compile_server: &mut CompileServer) { + match descriptor { + FunctionLogicDescriptor::Stub => todo!("{:?}", function), + FunctionLogicDescriptor::Clone(_) => todo!("{:?}", function), + FunctionLogicDescriptor::TraitProvider(trait_) => { + let uuid = trait_.id; + compile_server.function_inlines.insert(Rc::clone(function), Rc::new(move |compiler, expression| { + unsafe { compiler.chunk.constants.push(Value { ptr: uuid_to_ptr(uuid) }); } + compiler.chunk.push_with_u32(OpCode::LOAD_CONSTANT_32, u32::try_from(compiler.chunk.constants.len() - 1).unwrap()); + Ok(()) + })); + } + FunctionLogicDescriptor::FunctionProvider(f) => { + let uuid = f.function_id; + compile_server.function_inlines.insert(Rc::clone(function), Rc::new(move |compiler, expression| { + unsafe { compiler.chunk.constants.push(Value { ptr: uuid_to_ptr(uuid) }); } + compiler.chunk.push_with_u32(OpCode::LOAD_CONSTANT_32, u32::try_from(compiler.chunk.constants.len() - 1).unwrap()); + Ok(()) + })); + } + FunctionLogicDescriptor::PrimitiveOperation { .. } => todo!("{:?}", descriptor), + FunctionLogicDescriptor::Constructor(struct_info) => { + let data_layout = compile_server.get_data_layout(struct_info); + + compile_server.function_inlines.insert(Rc::clone(function), Rc::new(move |compiler, expression| { + let arguments = &compiler.implementation.expression_tree.children[&expression]; + assert_eq!(arguments.len(), data_layout.fields.len() + 1); + + compiler.chunk.push_with_u32(OpCode::ALLOC_32, u32::try_from(data_layout.fields.len()).unwrap()); + for (idx, arg) in arguments.iter().skip(1).enumerate() { + // If needed, duplicate the object pointer. + if idx < arguments.len() - 1 { + compiler.chunk.push(OpCode::DUP64); + } + + // Evaluate the field at the given index. + compiler.compile_expression(arg)?; + compiler.chunk.push_with_u32(OpCode::SET_MEMBER_32, u32::try_from(idx).unwrap()); + } + + Ok(()) + })); + } + FunctionLogicDescriptor::GetMemberField(struct_info, ref_) => { + let data_layout = compile_server.get_data_layout(struct_info); + let slot_index = data_layout.fields.iter().position(|r| r == ref_).unwrap(); + + compile_server.function_inlines.insert(Rc::clone(function), Rc::new(move |compiler, expression| { + let arguments = &compiler.implementation.expression_tree.children[&expression]; + + compiler.compile_expression(&arguments[0])?; + + compiler.chunk.push_with_u32(OpCode::GET_MEMBER_32, u32::try_from(slot_index).unwrap()); + + Ok(()) + })); + } + FunctionLogicDescriptor::SetMemberField(struct_info, ref_) => { + let data_layout = compile_server.get_data_layout(struct_info); + let slot_index = data_layout.fields.iter().position(|r| r == ref_).unwrap(); + + compile_server.function_inlines.insert(Rc::clone(function), Rc::new(move |compiler, expression| { + let arguments = &compiler.implementation.expression_tree.children[&expression]; + + compiler.compile_expression(&arguments[0])?; + compiler.compile_expression(&arguments[1])?; + + compiler.chunk.push_with_u32(OpCode::SET_MEMBER_32, u32::try_from(slot_index).unwrap()); + + Ok(()) + })); + } + } +} diff --git a/src/interpreter/data_layout.rs b/src/interpreter/data_layout.rs index 21d7cce..fa63774 100644 --- a/src/interpreter/data_layout.rs +++ b/src/interpreter/data_layout.rs @@ -1,6 +1,7 @@ use std::rc::Rc; + use itertools::Itertools; -use crate::interpreter::runtime::Runtime; + use crate::program::allocation::ObjectReference; use crate::program::traits::StructInfo; use crate::program::types::TypeUnit; @@ -10,7 +11,7 @@ pub struct DataLayout { pub fields: Vec>, } -pub fn create_data_layout(runtime: &mut Runtime, struct_info: Rc) -> Rc { +pub fn create_data_layout(struct_info: Rc) -> Rc { let mut fields = vec![]; let mut todo = struct_info.fields.iter().rev().collect_vec(); diff --git a/src/interpreter/run.rs b/src/interpreter/run.rs index 50aada9..218990b 100644 --- a/src/interpreter/run.rs +++ b/src/interpreter/run.rs @@ -3,7 +3,6 @@ use std::rc::Rc; use uuid::Uuid; use crate::error::{RResult, RuntimeError}; -use crate::interpreter::compile::function_compiler::compile_deep; use crate::interpreter::data::Value; use crate::interpreter::runtime::Runtime; use crate::interpreter::vm::VM; @@ -16,7 +15,7 @@ pub fn main(module: &Module, runtime: &mut Runtime) -> RResult<()> { .ok_or(RuntimeError::error("No main! function declared.").to_array())?; // TODO Should gather all used functions and compile them - let compiled = compile_deep(runtime, entry_function)?; + let compiled = runtime.compile_server.compile_deep(&runtime.source, entry_function)?; let mut out = std::io::stdout(); let mut vm = VM::new(&mut out); @@ -48,7 +47,7 @@ pub fn transpile(module: &Module, runtime: &mut Runtime) -> RResult>>, pub traits: Option, - // These are optimized for running and may not reflect the source code itself. - // They are also only loaded on demand. - pub function_evaluators: HashMap>, - // TODO We'll need these only in the future when we compile functions to constants. - // pub global_assignments: HashMap, - pub function_inlines: HashMap, InlineFunction>, - pub data_layouts: HashMap, Rc>, + pub compile_server: CompileServer, // These remain unchanged after resolution. pub source: Source, @@ -48,9 +37,7 @@ impl Runtime { Metatype: Rc::clone(&Metatype), primitives: None, traits: None, - function_evaluators: Default::default(), - function_inlines: Default::default(), - data_layouts: Default::default(), + compile_server: CompileServer::new(), source: Source::new(), repository: Repository::new(), }); @@ -120,14 +107,4 @@ impl Runtime { resolver::resolve_file(syntax, &scope, self, &mut module)?; Ok(module) } - - pub fn get_data_layout(&mut self, struct_info: &Rc) -> Rc { - if let Some(layout) = self.data_layouts.get(struct_info) { - return Rc::clone(layout) - } - - let layout = create_data_layout(self, Rc::clone(struct_info)); - self.data_layouts.insert(Rc::clone(struct_info), Rc::clone(&layout)); - layout - } } diff --git a/src/interpreter/tests.rs b/src/interpreter/tests.rs index 3b7bae9..a71c6e2 100644 --- a/src/interpreter/tests.rs +++ b/src/interpreter/tests.rs @@ -1,17 +1,15 @@ #[cfg(test)] mod tests { use std::path::PathBuf; - use std::ptr::read_unaligned; use std::rc::Rc; + use crate::error::RResult; use crate::interpreter; use crate::interpreter::chunks::Chunk; - use crate::interpreter::compile::function_compiler::compile_deep; - use crate::interpreter::data::Value; use crate::interpreter::opcode::{OpCode, Primitive}; use crate::interpreter::runtime::Runtime; use crate::interpreter::vm::VM; - use crate::program::module::{Module, module_name}; + use crate::program::module::module_name; use crate::transpiler::LanguageContext; /// This tests the transpiler, interpreter and function calls. @@ -51,7 +49,7 @@ mod tests { let entry_function = interpreter::run::get_main_function(&module)?.unwrap(); // TODO Should gather all used functions and compile them - let compiled = compile_deep(&mut runtime, entry_function)?; + let compiled = runtime.compile_server.compile_deep(&runtime.source, entry_function)?; let mut out: Vec = vec![]; let mut vm = VM::new(&mut out); @@ -155,7 +153,7 @@ mod tests { let entry_function = interpreter::run::get_main_function(&module)?.unwrap(); // TODO Should gather all used functions and compile them - let compiled = compile_deep(&mut runtime, entry_function)?; + let compiled = runtime.compile_server.compile_deep(&runtime.source, entry_function)?; let mut out: Vec = vec![]; let mut vm = VM::new(&mut out); diff --git a/src/interpreter/vm.rs b/src/interpreter/vm.rs index ab67989..062a85d 100644 --- a/src/interpreter/vm.rs +++ b/src/interpreter/vm.rs @@ -1,19 +1,21 @@ -pub mod call_frame; - use std::alloc::{alloc, Layout}; -use std::mem::{swap, transmute}; -use monoteny_macro::{bin_expr, pop_ip, pop_sp, un_expr}; -use std::ptr::{read_unaligned, write_unaligned}; -use uuid::Uuid; +use std::mem::transmute; use std::ops::Neg; +use std::ptr::{read_unaligned, write_unaligned}; use std::rc::Rc; -use crate::error::{RuntimeError, RResult}; + +use monoteny_macro::{bin_expr, pop_ip, pop_sp, un_expr}; +use uuid::Uuid; + +use crate::error::{RResult, RuntimeError}; use crate::interpreter::chunks::Chunk; use crate::interpreter::data::{string_to_ptr, Value}; use crate::interpreter::opcode::{OpCode, Primitive}; use crate::interpreter::runtime::Runtime; use crate::interpreter::vm::call_frame::CallFrame; +pub mod call_frame; + pub struct VM<'b> { pub pipe_out: &'b mut dyn std::io::Write, pub stack: Vec, @@ -83,7 +85,7 @@ impl<'b> VM<'b> { }, OpCode::CALL => { let uuid = Uuid::from_u128(pop_ip!(u128)); - let chunk = Rc::clone(&runtime.function_evaluators[&uuid]); + let chunk = Rc::clone(&runtime.compile_server.function_evaluators[&uuid]); self.call_frames.push(CallFrame { chunk: current_chunk, fp, diff --git a/src/refactor.rs b/src/refactor.rs index 9f8c56c..ed9fb40 100644 --- a/src/refactor.rs +++ b/src/refactor.rs @@ -5,11 +5,11 @@ use std::rc::Rc; use itertools::Itertools; use linked_hash_set::LinkedHashSet; -use crate::interpreter::runtime::Runtime; use crate::program::functions::{FunctionBinding, FunctionHead, FunctionImplementation, FunctionLogic, FunctionLogicDescriptor, FunctionType}; use crate::refactor::call_graph::CallGraph; use crate::refactor::inline::{inline_calls, InlineHint, try_inline}; use crate::refactor::monomorphize::monomorphize_implementation; +use crate::source::Source; pub mod simplify; pub mod monomorphize; @@ -119,12 +119,12 @@ impl Refactor { } } - pub fn try_monomorphize(&mut self, binding: &Rc, runtime: &mut Runtime) -> Option> { + pub fn try_monomorphize(&mut self, binding: &Rc, source: &Source) -> Option> { if self.fn_optimizations.contains_key(binding) { return None // We already have an optimization; we need not monomorphize. } - let Some(logic) = self.fn_logic.get(&binding.function).or_else(|| runtime.source.fn_logic.get(&binding.function)) else { + let Some(logic) = self.fn_logic.get(&binding.function).or_else(|| source.fn_logic.get(&binding.function)) else { panic!("Cannot find logic for function {:?}", binding.function); }; @@ -194,11 +194,11 @@ impl Refactor { } } - pub fn gather_needed_functions(&mut self, runtime: &mut Runtime) -> LinkedHashSet> { + pub fn gather_needed_functions(&mut self, source: &Source) -> LinkedHashSet> { let callees = self.call_graph.deep_callees(self.explicit_functions.iter()); for callee in callees.iter() { if !self.fn_logic.contains_key(callee) { - self.fn_logic.insert(Rc::clone(callee), runtime.source.fn_logic[callee].clone()); + self.fn_logic.insert(Rc::clone(callee), source.fn_logic[callee].clone()); } } callees diff --git a/src/refactor/simplify.rs b/src/refactor/simplify.rs index 4e7764b..f1a69b9 100644 --- a/src/refactor/simplify.rs +++ b/src/refactor/simplify.rs @@ -1,33 +1,20 @@ use std::collections::hash_map::RandomState; use linked_hash_set::LinkedHashSet; -use crate::interpreter::runtime::Runtime; + use crate::program::functions::FunctionLogic; use crate::refactor::{locals, Refactor}; -use crate::transpiler::Config; +use crate::source::Source; -pub struct Simplify<'a> { - pub refactor: &'a mut Refactor, +pub struct Simplify { + pub refactor: Refactor, pub inline: bool, pub trim_locals: bool, pub monomorphize: bool, } -impl<'a> Simplify<'a> { - pub fn new(refactor: &'a mut Refactor, config: &Config) -> Simplify<'a> { - if !config.should_monomorphize { - todo!(); // Lots of reasons non-monomorphization doesn't work right now. - } - - Simplify { - refactor, - inline: config.should_inline, - trim_locals: config.should_trim_locals, - monomorphize: config.should_monomorphize, - } - } - - pub fn run(&mut self, runtime: &mut Runtime) { +impl Simplify { + pub fn run(&mut self, source: &Source) { if self.monomorphize { // First, monomorphize everything we call let mut next: LinkedHashSet<_, RandomState> = LinkedHashSet::from_iter( @@ -35,14 +22,14 @@ impl<'a> Simplify<'a> { .flat_map(|head| self.refactor.call_graph.callees[head].iter().cloned()) ); while let Some(current) = next.pop_front() { - if let Some(monomorphized) = self.refactor.try_monomorphize(¤t, runtime) { + if let Some(monomorphized) = self.refactor.try_monomorphize(¤t, source) { next.extend(self.refactor.call_graph.callees.get(&monomorphized).unwrap().iter().cloned()); } } } // Make sure refactor has everything that's needed so we can simplify it. - self.refactor.gather_needed_functions(runtime); + self.refactor.gather_needed_functions(source); // Now, let's simplify! let mut next: LinkedHashSet<_, RandomState> = LinkedHashSet::from_iter(self.refactor.fn_logic.keys().cloned()); diff --git a/src/transpiler.rs b/src/transpiler.rs index c199368..2c0156e 100644 --- a/src/transpiler.rs +++ b/src/transpiler.rs @@ -73,17 +73,27 @@ pub fn transpile(transpiler: Box, runtime: &mut Runtime, context: &d } } - let mut simplify = Simplify::new(&mut refactor, config); - simplify.run(runtime); + if !config.should_monomorphize { + todo!(); // Lots of reasons non-monomorphization doesn't work right now. + } + + let mut simplify = Simplify { + refactor, + inline: config.should_inline, + trim_locals: config.should_trim_locals, + monomorphize: config.should_monomorphize, + }; + + simplify.run(&runtime.source); // --- Reclaim from Refactor and make the ast - context.refactor_code(&mut refactor); + context.refactor_code(&mut simplify.refactor); // TODO The call_graph doesn't know about calls made outside the refactor. If there was no monomorphization, some functions may not even be caught by this. - let deep_calls = refactor.gather_needed_functions(runtime); - let mut fn_logic = refactor.fn_logic; + let deep_calls = simplify.refactor.gather_needed_functions(&runtime.source); + let mut fn_logic = simplify.refactor.fn_logic; - let exported_functions = refactor.explicit_functions.iter() + let exported_functions = simplify.refactor.explicit_functions.iter() .map(|head| fn_logic.get(head).unwrap().as_implementation()) .try_collect_many()?; let mut implicit_functions = vec![];