From ab9678405484a39ef38a950594b114d91bebcf5f Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Tue, 4 Oct 2022 17:49:15 +0200 Subject: [PATCH 01/44] Refactor tracing --- compiler/src/fuzzer/fuzzer.rs | 40 +- compiler/src/fuzzer/generator.rs | 15 +- compiler/src/fuzzer/mod.rs | 22 +- compiler/src/fuzzer/utils.rs | 75 ++-- .../hints/constant_evaluator.rs | 76 ++-- compiler/src/language_server/hints/fuzzer.rs | 57 ++- compiler/src/main.rs | 61 +-- compiler/src/vm/builtin_functions.rs | 11 +- compiler/src/vm/channel.rs | 10 +- compiler/src/vm/context.rs | 6 +- compiler/src/vm/fiber.rs | 94 ++-- compiler/src/vm/heap/mod.rs | 52 ++- compiler/src/vm/mod.rs | 38 +- compiler/src/vm/tracer.rs | 400 ------------------ compiler/src/vm/tracer/full_trace.rs | 201 +++++++++ compiler/src/vm/tracer/mod.rs | 225 ++++++++++ compiler/src/vm/tracer/stack_trace.rs | 131 ++++++ compiler/src/vm/use_module.rs | 11 +- 18 files changed, 862 insertions(+), 663 deletions(-) delete mode 100644 compiler/src/vm/tracer.rs create mode 100644 compiler/src/vm/tracer/full_trace.rs create mode 100644 compiler/src/vm/tracer/mod.rs create mode 100644 compiler/src/vm/tracer/stack_trace.rs diff --git a/compiler/src/fuzzer/fuzzer.rs b/compiler/src/fuzzer/fuzzer.rs index 64d8df2a7..16d569eb2 100644 --- a/compiler/src/fuzzer/fuzzer.rs +++ b/compiler/src/fuzzer/fuzzer.rs @@ -5,10 +5,11 @@ use crate::{ vm::{ self, context::{ExecutionController, UseProvider}, - tracer::Tracer, - Closure, Heap, Pointer, TearDownResult, Vm, + tracer::{DummyTracer, FullTracer}, + Closure, Heap, Packet, Pointer, Vm, }, }; +use itertools::Itertools; use std::mem; pub struct Fuzzer { @@ -24,15 +25,15 @@ pub enum Status { // input that triggers the loop. StillFuzzing { vm: Vm, - arguments: Vec, + arguments: Vec, + tracer: FullTracer, }, // TODO: In the future, also add a state for trying to simplify the // arguments. PanickedForArguments { - heap: Heap, - arguments: Vec, + arguments: Vec, reason: String, - tracer: Tracer, + tracer: FullTracer, }, } @@ -45,12 +46,20 @@ impl Status { let mut vm_heap = Heap::default(); let closure = closure_heap.clone_single_to_other_heap(&mut vm_heap, closure); - let arguments = generate_n_values(&mut vm_heap, num_args); + let arguments = generate_n_values(num_args); + let argument_addresses = arguments + .iter() + .map(|arg| arg.clone_to_other_heap(&mut vm_heap)) + .collect_vec(); let mut vm = Vm::new(); - vm.set_up_for_running_closure(vm_heap, closure, &arguments); + vm.set_up_for_running_closure(vm_heap, closure, &argument_addresses); - Status::StillFuzzing { vm, arguments } + Status::StillFuzzing { + vm, + arguments, + tracer: FullTracer::new(), + } } } impl Fuzzer { @@ -94,10 +103,10 @@ impl Fuzzer { execution_controller: &mut E, ) -> Status { match status { - Status::StillFuzzing { mut vm, arguments } => match vm.status() { + Status::StillFuzzing { mut vm, arguments, tracer } => match vm.status() { vm::Status::CanRun => { - vm.run(use_provider, execution_controller); - Status::StillFuzzing { vm, arguments } + vm.run(use_provider, execution_controller, &mut DummyTracer); + Status::StillFuzzing { vm, arguments, tracer } } vm::Status::WaitingForOperations => panic!("Fuzzing should not have to wait on channel operations because arguments were not channels."), // The VM finished running without panicking. @@ -106,14 +115,13 @@ impl Fuzzer { // If a `needs` directly inside the tested closure was not // satisfied, then the panic is not closure's fault, but our // fault. - let TearDownResult { heap, tracer, .. } = vm.tear_down(); + let result = vm.tear_down(); let is_our_fault = - did_need_in_closure_cause_panic(db, &self.closure_id, &tracer); + did_need_in_closure_cause_panic(db, &self.closure_id); if is_our_fault { Status::new_fuzzing_attempt(&self.closure_heap, self.closure) } else { Status::PanickedForArguments { - heap, arguments, reason, tracer, @@ -124,12 +132,10 @@ impl Fuzzer { // We already found some arguments that caused the closure to panic, // so there's nothing more to do. Status::PanickedForArguments { - heap, arguments, reason, tracer, } => Status::PanickedForArguments { - heap, arguments, reason, tracer, diff --git a/compiler/src/fuzzer/generator.rs b/compiler/src/fuzzer/generator.rs index 257464609..64bf0096b 100644 --- a/compiler/src/fuzzer/generator.rs +++ b/compiler/src/fuzzer/generator.rs @@ -2,21 +2,26 @@ use std::collections::HashMap; use crate::{ builtin_functions, - vm::{Heap, Pointer}, + vm::{Heap, Packet, Pointer}, }; use num_bigint::RandBigInt; use rand::{prelude::ThreadRng, Rng}; -pub fn generate_n_values(heap: &mut Heap, n: usize) -> Vec { +pub fn generate_n_values(n: usize) -> Vec { let mut values = vec![]; for _ in 0..n { - values.push(generate_value(heap)); + values.push(generate_value()); } values } -fn generate_value(heap: &mut Heap) -> Pointer { - generate_value_with_complexity(heap, &mut rand::thread_rng(), 100.0) +fn generate_value() -> Packet { + let mut heap = Heap::default(); + let value = generate_value_with_complexity(&mut heap, &mut rand::thread_rng(), 100.0); + Packet { + heap, + address: value, + } } fn generate_value_with_complexity( heap: &mut Heap, diff --git a/compiler/src/fuzzer/mod.rs b/compiler/src/fuzzer/mod.rs index 03f902f69..a4606a14f 100644 --- a/compiler/src/fuzzer/mod.rs +++ b/compiler/src/fuzzer/mod.rs @@ -4,23 +4,25 @@ mod utils; pub use self::fuzzer::{Fuzzer, Status}; use crate::{ + compiler::hir::Id, database::Database, module::Module, vm::{ context::{DbUseProvider, RunForever, RunLimitedNumberOfInstructions}, - Closure, Vm, + tracer::DummyTracer, + Closure, Heap, Pointer, Vm, }, }; use itertools::Itertools; use tracing::info; pub async fn fuzz(db: &Database, module: Module) { - let (fuzzables_heap, fuzzables) = { + let (fuzzables_heap, fuzzables): (Heap, Vec<(Id, Pointer)>) = { let mut vm = Vm::new(); vm.set_up_for_running_module_closure(Closure::of_module(db, module.clone()).unwrap()); - vm.run(&mut DbUseProvider { db }, &mut RunForever); + vm.run(&mut DbUseProvider { db }, &mut RunForever, &mut DummyTracer); let result = vm.tear_down(); - (result.heap, result.fuzzable_closures) + (todo!(), todo!()) }; info!( @@ -38,7 +40,6 @@ pub async fn fuzz(db: &Database, module: Module) { match fuzzer.status() { Status::StillFuzzing { .. } => {} Status::PanickedForArguments { - heap, arguments, reason, tracer, @@ -46,15 +47,14 @@ pub async fn fuzz(db: &Database, module: Module) { info!("The fuzzer discovered an input that crashes {id}:"); info!( "Calling `{id} {}` doesn't work because {reason}.", - arguments - .iter() - .map(|argument| argument.format(heap)) - .join(" "), + arguments.iter().map(|arg| format!("{arg:?}")).join(" "), ); info!("This was the stack trace:"); - tracer.dump_stack_trace(db, heap); + // tracer.dump_stack_trace(db); + todo!(); - module.dump_associated_debug_file("trace", &tracer.full_trace().format(heap)); + // module.dump_associated_debug_file("trace", &tracer.full_trace().format(heap)); + todo!(); } } } diff --git a/compiler/src/fuzzer/utils.rs b/compiler/src/fuzzer/utils.rs index a25bbfd22..7d94e6337 100644 --- a/compiler/src/fuzzer/utils.rs +++ b/compiler/src/fuzzer/utils.rs @@ -1,46 +1,47 @@ use crate::{ compiler::hir::{self, Expression, HirDb, Lambda}, database::Database, - vm::tracer::{EventData, Tracer}, + vm::tracer::{FullTracer, Tracer}, }; -pub fn did_need_in_closure_cause_panic( - db: &Database, - closure_id: &hir::Id, - tracer: &Tracer, -) -> bool { - let entry = if let Some(entry) = tracer.events.last() { - entry - } else { - // The only way there's no trace log before the panic is when there's an - // error from an earlier compilation stage that got lowered into the - // LIR. That's also definitely the fault of the function. - return false; - }; - if let EventData::NeedsStarted { id, .. } = &entry.data { - let mut id = id.parent().unwrap(); - loop { - if &id == closure_id { - return true; - } +pub fn did_need_in_closure_cause_panic(db: &Database, closure_id: &hir::Id) -> bool { + todo!(); + // let entry = if let Some(entry) = tracer.events.last() { + // entry + // } else { + // // The only way there's no trace log before the panic is when there's an + // // error from an earlier compilation stage that got lowered into the + // // LIR. That's also definitely the fault of the function. + // return false; + // }; + // if let Event::InFiber { + // event: InFiberEvent::NeedsStarted { id, .. }, + // .. + // } = &entry.data + // { + // let mut id = id.parent().unwrap(); + // loop { + // if &id == closure_id { + // return true; + // } - match db - .find_expression(id.clone()) - .expect("Parent of a `needs` call is a parameter.") - { - Expression::Lambda(Lambda { fuzzable, .. }) => { - if fuzzable { - return false; // The needs is in a different fuzzable lambda. - } - } - _ => panic!("Only lambdas can be the parent of a `needs` call."), - }; + // match db + // .find_expression(id.clone()) + // .expect("Parent of a `needs` call is a parameter.") + // { + // Expression::Lambda(Lambda { fuzzable, .. }) => { + // if fuzzable { + // return false; // The needs is in a different fuzzable lambda. + // } + // } + // _ => panic!("Only lambdas can be the parent of a `needs` call."), + // }; - match id.parent() { - Some(parent_id) => id = parent_id, - None => return false, - } - } - } + // match id.parent() { + // Some(parent_id) => id = parent_id, + // None => return false, + // } + // } + // } false } diff --git a/compiler/src/language_server/hints/constant_evaluator.rs b/compiler/src/language_server/hints/constant_evaluator.rs index f8aea9e7a..5de1ae782 100644 --- a/compiler/src/language_server/hints/constant_evaluator.rs +++ b/compiler/src/language_server/hints/constant_evaluator.rs @@ -12,8 +12,8 @@ use crate::{ vm::{ self, context::{DbUseProvider, RunLimitedNumberOfInstructions}, - tracer::{EventData, StackEntry}, - Closure, Heap, Pointer, TearDownResult, Vm, + tracer::{stack_trace::StackEntry, DummyTracer, FullTracer}, + Closure, Heap, Pointer, Vm, }, }; use itertools::Itertools; @@ -54,6 +54,7 @@ impl ConstantEvaluator { vm.run( &mut DbUseProvider { db }, &mut RunLimitedNumberOfInstructions::new(500), + &mut DummyTracer, ); Some(module.clone()) } else { @@ -63,12 +64,9 @@ impl ConstantEvaluator { pub fn get_fuzzable_closures(&self, module: &Module) -> (Heap, Vec<(Id, Pointer)>) { let vm = &self.vms[module]; - let TearDownResult { - heap, - fuzzable_closures, - .. - } = vm.clone().tear_down(); - (heap, fuzzable_closures) + let result = vm.clone().tear_down(); + // (heap, fuzzable_closures) + todo!() } pub fn get_hints(&self, db: &Database, module: &Module) -> Vec { @@ -84,34 +82,36 @@ impl ConstantEvaluator { } }; - let TearDownResult { heap, tracer, .. } = vm.clone().tear_down(); + // let TearDownResult { heap, tracer, .. } = vm.clone().tear_down(); + let heap: Heap = todo!(); + let tracer: FullTracer = todo!(); for entry in &tracer.events { - if let EventData::ValueEvaluated { id, value } = &entry.data { - if &id.module != module { - continue; - } - let ast_id = match db.hir_to_ast_id(id.clone()) { - Some(ast_id) => ast_id, - None => continue, - }; - let ast = match db.ast(module.clone()) { - Some((ast, _)) => (*ast).clone(), - None => continue, - }; - let ast = match ast.find(&ast_id) { - Some(ast) => ast, - None => continue, - }; - if !matches!(ast.kind, AstKind::Assignment(_)) { - continue; - } - - hints.push(Hint { - kind: HintKind::Value, - text: value.format(&heap), - position: id_to_end_of_line(db, id.clone()).unwrap(), - }); - } + // if let EventData::ValueEvaluated { id, value } = &entry.data { + // if &id.module != module { + // continue; + // } + // let ast_id = match db.hir_to_ast_id(id.clone()) { + // Some(ast_id) => ast_id, + // None => continue, + // }; + // let ast = match db.ast(module.clone()) { + // Some((ast, _)) => (*ast).clone(), + // None => continue, + // }; + // let ast = match ast.find(&ast_id) { + // Some(ast) => ast, + // None => continue, + // }; + // if !matches!(ast.kind, AstKind::Assignment(_)) { + // continue; + // } + + // hints.push(Hint { + // kind: HintKind::Value, + // text: value.format(&heap), + // position: id_to_end_of_line(db, id.clone()).unwrap(), + // }); + // } } hints @@ -122,8 +122,10 @@ fn panic_hint(db: &Database, module: Module, vm: &Vm, reason: String) -> Option< // We want to show the hint at the last call site still inside the current // module. If there is no call site in this module, then the panic results // from a compiler error in a previous stage which is already reported. - let TearDownResult { heap, tracer, .. } = vm.clone().tear_down(); - let stack = tracer.stack_trace(); + let heap: Heap = todo!(); // vm.clone().tear_down(); + let tracer: FullTracer = todo!(); + // let stack = tracer.stack_trace(); + let stack: Vec = todo!(); if stack.len() == 1 { // The stack only contains an `InModule` entry. This indicates an error // during compilation resulting in a top-level error instruction. diff --git a/compiler/src/language_server/hints/fuzzer.rs b/compiler/src/language_server/hints/fuzzer.rs index b4e33d88b..677197b7f 100644 --- a/compiler/src/language_server/hints/fuzzer.rs +++ b/compiler/src/language_server/hints/fuzzer.rs @@ -9,7 +9,6 @@ use crate::{ module::Module, vm::{ context::{DbUseProvider, RunLimitedNumberOfInstructions}, - tracer::EventData, Heap, Pointer, }, }; @@ -71,7 +70,6 @@ impl FuzzerManager { for fuzzer in self.fuzzers[module].values() { if let Status::PanickedForArguments { - heap, arguments, reason, tracer, @@ -97,10 +95,7 @@ impl FuzzerManager { parameter_names .iter() .zip(arguments.iter()) - .map(|(name, argument)| format!( - "`{name} = {}`", - argument.format(heap) - )) + .map(|(name, argument)| format!("`{name} = {argument:?}`")) .collect_vec() .join_with_commas_and_and(), ), @@ -116,11 +111,12 @@ impl FuzzerManager { // Find the innermost panicking call that is in the // function. .find(|entry| { - let innermost_panicking_call_id = match &entry.data { - EventData::CallStarted { id, .. } => id, - EventData::NeedsStarted { id, .. } => id, - _ => return false, - }; + let innermost_panicking_call_id = todo!(); + // match &entry.event { + // EventData::CallStarted { id, .. } => id, + // EventData::NeedsStarted { id, .. } => id, + // _ => return false, + // }; id.is_same_module_and_any_parent_of(innermost_panicking_call_id) && db.hir_to_cst_id(id.clone()).is_some() }); @@ -133,25 +129,26 @@ impl FuzzerManager { continue; } }; - let (call_id, name, arguments) = match &panicking_inner_call.data { - EventData::CallStarted { id, closure, args } => { - (id.clone(), closure.format(heap), args.clone()) - } - EventData::NeedsStarted { - id, - condition, - reason, - } => (id.clone(), "needs".to_string(), vec![*condition, *reason]), - _ => unreachable!(), - }; - Hint { - kind: HintKind::Fuzz, - text: format!( - "then `{name} {}` panics because {reason}.", - arguments.iter().map(|arg| arg.format(heap)).join(" "), - ), - position: id_to_end_of_line(db, call_id).unwrap(), - } + todo!() + // let (call_id, name, arguments) = match &panicking_inner_call.data { + // EventData::CallStarted { id, closure, args } => { + // (id.clone(), closure.format(heap), args.clone()) + // } + // EventData::NeedsStarted { + // id, + // condition, + // reason, + // } => (id.clone(), "needs".to_string(), vec![*condition, *reason]), + // _ => unreachable!(), + // }; + // Hint { + // kind: HintKind::Fuzz, + // text: format!( + // "then `{name} {}` panics because {reason}.", + // arguments.iter().map(|arg| arg.format(heap)).join(" "), + // ), + // position: id_to_end_of_line(db, call_id).unwrap(), + // } }; hints.push(vec![first_hint, second_hint]); diff --git a/compiler/src/main.rs b/compiler/src/main.rs index 25a456814..6d96521c2 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -1,5 +1,6 @@ #![feature(async_closure)] #![feature(box_patterns)] +#![feature(generic_associated_types)] #![feature(let_chains)] #![feature(never_type)] #![feature(try_trait_v2)] @@ -28,7 +29,8 @@ use crate::{ module::{Module, ModuleKind}, vm::{ context::{DbUseProvider, RunForever}, - Closure, Status, Struct, TearDownResult, Vm, + tracer::DummyTracer, + Closure, Status, Struct, Vm, }, }; use compiler::lir::Lir; @@ -212,7 +214,11 @@ fn run(options: CandyRunOptions) { match vm.status() { Status::CanRun => { debug!("VM still running."); - vm.run(&mut DbUseProvider { db: &db }, &mut RunForever); + vm.run( + &mut DbUseProvider { db: &db }, + &mut RunForever, + &mut DummyTracer, + ); } Status::WaitingForOperations => { todo!("VM can't proceed until some operations complete."); @@ -221,29 +227,30 @@ fn run(options: CandyRunOptions) { } } info!("Tree: {:#?}", vm); - let TearDownResult { - tracer, - result, - mut heap, - .. - } = vm.tear_down(); + let result = vm.tear_down(); if options.debug { - module.dump_associated_debug_file("trace", &tracer.full_trace().format(&heap)); + todo!(); + // module.dump_associated_debug_file("trace", &tracer.full_trace().format(&heap)); } - let exported_definitions: Struct = match result { + let (mut heap, exported_definitions): (_, Struct) = match result { Ok(return_value) => { - info!( - "The module exports these definitions: {}", - return_value.format(&heap), - ); - heap.get(return_value).data.clone().try_into().unwrap() + info!("The module exports these definitions: {return_value:?}",); + let exported = return_value + .heap + .get(return_value.address) + .data + .clone() + .try_into() + .unwrap(); + (return_value.heap, exported) } Err(reason) => { error!("The module panicked because {reason}."); error!("This is the stack trace:"); - tracer.dump_stack_trace(&db, &heap); + // tracer.dump_stack_trace(&db, &heap); + todo!(); return; } }; @@ -272,7 +279,11 @@ fn run(options: CandyRunOptions) { match vm.status() { Status::CanRun => { debug!("VM still running."); - vm.run(&mut DbUseProvider { db: &db }, &mut RunForever); + vm.run( + &mut DbUseProvider { db: &db }, + &mut RunForever, + &mut DummyTracer, + ); // TODO: handle operations } Status::WaitingForOperations => { @@ -292,7 +303,7 @@ fn run(options: CandyRunOptions) { performing_fiber, packet, } => { - info!("Sent to stdout: {}", packet.value.format(&packet.heap)); + info!("Sent to stdout: {}", packet.address.format(&packet.heap)); vm.complete_send(performing_fiber); } vm::Operation::Receive { .. } => unreachable!(), @@ -301,19 +312,13 @@ fn run(options: CandyRunOptions) { } } info!("Tree: {:#?}", vm); - let TearDownResult { - tracer, - result, - heap, - .. - } = vm.tear_down(); - - match result { - Ok(return_value) => info!("The main function returned: {}", return_value.format(&heap)), + match vm.tear_down() { + Ok(return_value) => info!("The main function returned: {return_value:?}"), Err(reason) => { error!("The main function panicked because {reason}."); error!("This is the stack trace:"); - tracer.dump_stack_trace(&db, &heap); + // tracer.dump_stack_trace(&db, &heap); + todo!(); } } } diff --git a/compiler/src/vm/builtin_functions.rs b/compiler/src/vm/builtin_functions.rs index 50e263a17..4272bc3e3 100644 --- a/compiler/src/vm/builtin_functions.rs +++ b/compiler/src/vm/builtin_functions.rs @@ -3,6 +3,7 @@ use super::{ context::PanickingUseProvider, fiber::{Fiber, Status}, heap::{ChannelId, Closure, Data, Int, Pointer, ReceivePort, SendPort, Struct, Symbol, Text}, + tracer::DummyInFiberTracer, Heap, }; use crate::{builtin_functions::BuiltinFunction, compiler::lir::Instruction}; @@ -64,7 +65,11 @@ impl Fiber { Ok(Return(value)) => self.data_stack.push(value), Ok(DivergeControlFlow { closure }) => { self.data_stack.push(closure); - self.run_instruction(&PanickingUseProvider, Instruction::Call { num_args: 0 }); + self.run_instruction( + &mut PanickingUseProvider, + &mut DummyInFiberTracer, + Instruction::Call { num_args: 0 }, + ); } Ok(CreateChannel { capacity }) => self.status = Status::CreatingChannel { capacity }, Ok(Send { channel, packet }) => self.status = Status::Sending { channel, packet }, @@ -153,10 +158,10 @@ impl Heap { fn channel_send(&mut self, args: &[Pointer]) -> BuiltinResult { unpack_and_later_drop!(self, args, |port: SendPort, packet: Any| { let mut heap = Heap::default(); - let value = self.clone_single_to_other_heap(&mut heap, packet.address); + let address = self.clone_single_to_other_heap(&mut heap, packet.address); Send { channel: port.channel, - packet: Packet { heap, value }, + packet: Packet { heap, address }, } }) } diff --git a/compiler/src/vm/channel.rs b/compiler/src/vm/channel.rs index 4ae8b00c4..757f1259a 100644 --- a/compiler/src/vm/channel.rs +++ b/compiler/src/vm/channel.rs @@ -20,7 +20,7 @@ pub type Capacity = usize; #[derive(Clone)] pub struct Packet { pub heap: Heap, - pub value: Pointer, + pub address: Pointer, } impl ChannelBuf { @@ -52,6 +52,12 @@ impl ChannelBuf { } } +impl Packet { + pub fn clone_to_other_heap(&self, other: &mut Heap) -> Pointer { + self.heap.clone_single_to_other_heap(other, self.address) + } +} + impl fmt::Debug for ChannelBuf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.packets.iter()).finish() @@ -59,6 +65,6 @@ impl fmt::Debug for ChannelBuf { } impl fmt::Debug for Packet { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.value.format(&self.heap)) + write!(f, "{}", self.address.format(&self.heap)) } } diff --git a/compiler/src/vm/context.rs b/compiler/src/vm/context.rs index 971b6c6ec..2720d150e 100644 --- a/compiler/src/vm/context.rs +++ b/compiler/src/vm/context.rs @@ -10,7 +10,7 @@ use crate::{ // of the VM. pub trait UseProvider { - fn use_module(&self, module: Module) -> Result; + fn use_module(&mut self, module: Module) -> Result; } pub enum UseResult { Asset(Vec), @@ -19,7 +19,7 @@ pub enum UseResult { pub struct PanickingUseProvider; impl UseProvider for PanickingUseProvider { - fn use_module(&self, _: Module) -> Result { + fn use_module(&mut self, _: Module) -> Result { panic!() } } @@ -28,7 +28,7 @@ pub struct DbUseProvider<'a> { pub db: &'a Database, } impl<'a> UseProvider for DbUseProvider<'a> { - fn use_module(&self, module: Module) -> Result { + fn use_module(&mut self, module: Module) -> Result { match module.kind { ModuleKind::Asset => match self.db.get_module_content(module.clone()) { Some(bytes) => Ok(UseResult::Asset((*bytes).clone())), diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index a89334033..ab00f1460 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -2,12 +2,12 @@ use super::{ channel::{Capacity, Packet}, context::{ExecutionController, UseProvider}, heap::{Builtin, ChannelId, Closure, Data, Heap, Pointer}, - tracer::{EventData, Tracer}, + tracer::InFiberTracer, }; use crate::{ - compiler::{hir::Id, lir::Instruction}, + compiler::lir::Instruction, module::Module, - vm::context::PanickingUseProvider, + vm::{context::PanickingUseProvider, tracer::DummyInFiberTracer}, }; use itertools::Itertools; use std::collections::HashMap; @@ -15,24 +15,16 @@ use tracing::trace; const TRACE: bool = false; -/// A fiber is one execution thread of a program. A fiber is always owned and -/// managed by a VM. A VM can own multiple fibers and run them concurrently. +/// A fiber represents an execution thread of a program. It's a stack-based +/// machine that runs instructions from a LIR. Fibers are owned by a `Vm`. #[derive(Clone)] pub struct Fiber { - // Core functionality to run code. Fibers are stack-based machines that run - // instructions from a LIR. All values are stored on a heap. pub status: Status, next_instruction: InstructionPointer, pub data_stack: Vec, pub call_stack: Vec, pub import_stack: Vec, pub heap: Heap, - - // Debug stuff. This is not essential to a correct working of the fiber, but - // enables advanced functionality like stack traces or finding out who's - // fault a panic is. - pub tracer: Tracer, - pub fuzzable_closures: Vec<(Id, Pointer)>, } #[derive(Clone, Debug)] @@ -70,13 +62,6 @@ impl InstructionPointer { } } -pub struct TearDownResult { - pub heap: Heap, - pub result: Result, - pub fuzzable_closures: Vec<(Id, Pointer)>, - pub tracer: Tracer, -} - impl Fiber { fn new_with_heap(heap: Heap) -> Self { Self { @@ -86,13 +71,11 @@ impl Fiber { call_stack: vec![], import_stack: vec![], heap, - tracer: Tracer::new(), - fuzzable_closures: vec![], } } pub fn new_for_running_closure(heap: Heap, closure: Pointer, arguments: &[Pointer]) -> Self { assert!( - !matches!(heap.get(closure).data, Data::Builtin(_),), + !matches!(heap.get(closure).data, Data::Builtin(_)), "can only use with closures, not builtins" ); @@ -103,7 +86,8 @@ impl Fiber { fiber.status = Status::Running; fiber.run_instruction( - &PanickingUseProvider, + &mut PanickingUseProvider, + &mut DummyInFiberTracer, Instruction::Call { num_args: arguments.len(), }, @@ -118,17 +102,14 @@ impl Fiber { Self::new_for_running_closure(heap, closure, &[]) } - pub fn tear_down(mut self) -> TearDownResult { - let result = match self.status { - Status::Done => Ok(self.data_stack.pop().unwrap()), + pub fn tear_down(mut self) -> Result { + match self.status { + Status::Done => Ok(Packet { + heap: self.heap, + address: self.data_stack.pop().unwrap(), + }), Status::Panicked { reason } => Err(reason), _ => panic!("Called `tear_down` on a fiber that's still running."), - }; - TearDownResult { - heap: self.heap, - result, - fuzzable_closures: self.fuzzable_closures, - tracer: self.tracer, } } @@ -155,7 +136,7 @@ impl Fiber { pub fn complete_receive(&mut self, packet: Packet) { let address = packet .heap - .clone_single_to_other_heap(&mut self.heap, packet.value); + .clone_single_to_other_heap(&mut self.heap, packet.address); self.data_stack.push(address); self.status = Status::Running; } @@ -172,7 +153,7 @@ impl Fiber { let result = match result { Ok(Packet { heap, - value: return_value, + address: return_value, }) => { let ok = self.heap.create_symbol("Ok".to_string()); let return_value = heap.clone_single_to_other_heap(&mut self.heap, return_value); @@ -195,10 +176,11 @@ impl Fiber { self.status = Status::Panicked { reason }; } - pub fn run( + pub fn run( &mut self, - use_provider: &mut U, - execution_controller: &mut E, + use_provider: &mut dyn UseProvider, + execution_controller: &mut dyn ExecutionController, + tracer: &mut dyn InFiberTracer, ) { assert!( matches!(self.status, Status::Running), @@ -240,7 +222,7 @@ impl Fiber { } self.next_instruction.instruction += 1; - self.run_instruction(use_provider, instruction); + self.run_instruction(use_provider, tracer, instruction); execution_controller.instruction_executed(); if self.next_instruction == InstructionPointer::null_pointer() { @@ -248,7 +230,12 @@ impl Fiber { } } } - pub fn run_instruction(&mut self, use_provider: &U, instruction: Instruction) { + pub fn run_instruction( + &mut self, + use_provider: &mut dyn UseProvider, + tracer: &mut dyn InFiberTracer, + instruction: Instruction, + ) { match instruction { Instruction::CreateInt(int) => { let address = self.heap.create_int(int.into()); @@ -401,12 +388,12 @@ impl Fiber { panic!("Instruction RegisterFuzzableClosure executed, but stack top is not a closure."); } self.heap.dup(closure); - self.fuzzable_closures.push((id, closure)); + tracer.found_fuzzable_closure(&self.heap, id, closure); } Instruction::TraceValueEvaluated(id) => { let value = *self.data_stack.last().unwrap(); self.heap.dup(value); - self.tracer.push(EventData::ValueEvaluated { id, value }); + tracer.value_evaluated(&self.heap, id, value); } Instruction::TraceCallStarts { id, num_args } => { let closure = *self.data_stack.last().unwrap(); @@ -421,29 +408,30 @@ impl Fiber { } args.reverse(); - self.tracer - .push(EventData::CallStarted { id, closure, args }); + tracer.call_started(&self.heap, id, closure, args); } Instruction::TraceCallEnds => { let return_value = *self.data_stack.last().unwrap(); self.heap.dup(return_value); - self.tracer.push(EventData::CallEnded { return_value }); + tracer.call_ended(&self.heap, return_value); } Instruction::TraceNeedsStarts { id } => { let condition = self.data_stack[self.data_stack.len() - 2]; let reason = self.data_stack[self.data_stack.len() - 1]; self.heap.dup(condition); self.heap.dup(reason); - self.tracer.push(EventData::NeedsStarted { - id, - condition, - reason, - }); + // TODO: Trace or remove this after fault analysis works. + // self.tracer.push(EventData::NeedsStarted { + // id, + // condition, + // reason, + // }); } Instruction::TraceNeedsEnds => { let nothing = *self.data_stack.last().unwrap(); self.heap.dup(nothing); - self.tracer.push(EventData::NeedsEnded { nothing }); + // TODO: Trace or remove this after fault analysis works. + // self.tracer.push(EventData::NeedsEnded { nothing }); } Instruction::TraceModuleStarts { module } => { if self.import_stack.contains(&module) { @@ -458,13 +446,13 @@ impl Fiber { )); } self.import_stack.push(module.clone()); - self.tracer.push(EventData::ModuleStarted { module }); + tracer.module_started(module); } Instruction::TraceModuleEnds => { self.import_stack.pop().unwrap(); let export_map = *self.data_stack.last().unwrap(); self.heap.dup(export_map); - self.tracer.push(EventData::ModuleEnded { export_map }) + tracer.module_ended(&self.heap, export_map); } Instruction::Error { id, errors } => { self.panic(format!( diff --git a/compiler/src/vm/heap/mod.rs b/compiler/src/vm/heap/mod.rs index f0269bb85..01494d5fd 100644 --- a/compiler/src/vm/heap/mod.rs +++ b/compiler/src/vm/heap/mod.rs @@ -104,9 +104,7 @@ impl Heap { } pub fn create(&mut self, object: Data) -> Pointer { - let address = self.next_address; - self.next_address = Pointer::from_raw(self.next_address.raw() + 1); - + let address = self.reserve_address(); let object = Object { reference_count: 1, data: object, @@ -115,6 +113,11 @@ impl Heap { self.objects.insert(address, object); address } + fn reserve_address(&mut self) -> Pointer { + let address = self.next_address; + self.next_address = Pointer::from_raw(self.next_address.raw() + 1); + address + } fn free(&mut self, address: Pointer) { let object = self.objects.remove(&address).unwrap(); trace!("Freeing object at {address}."); @@ -126,36 +129,32 @@ impl Heap { /// Clones all objects at the `root_addresses` into the `other` heap and /// returns a list of their addresses in the other heap. - pub fn clone_multiple_to_other_heap( + pub fn clone_multiple_to_other_heap_with_existing_mapping( &self, other: &mut Heap, addresses: &[Pointer], + address_map: &mut HashMap, ) -> Vec { let mut objects_to_refcounts = HashMap::new(); for address in addresses { self.gather_objects_to_clone(&mut objects_to_refcounts, *address); } - let num_objects = objects_to_refcounts.len(); - let address_map: HashMap = objects_to_refcounts - .keys() - .copied() - .zip( - (other.next_address.raw()..other.next_address.raw() + num_objects) - .map(Pointer::from_raw), - ) - .collect(); + for object in objects_to_refcounts.keys() { + address_map + .entry(*object) + .or_insert_with(|| other.reserve_address()); + } for (address, refcount) in objects_to_refcounts { other.objects.insert( address_map[&address], Object { reference_count: refcount, - data: Self::map_data(&address_map, &self.get(address).data), + data: Self::map_data(address_map, &self.get(address).data), }, ); } - other.next_address = Pointer::from_raw(other.next_address.raw() + num_objects); addresses .iter() @@ -198,11 +197,30 @@ impl Heap { Data::ReceivePort(port) => Data::ReceivePort(ReceivePort::new(port.channel)), } } - pub fn clone_single_to_other_heap(&self, other: &mut Heap, address: Pointer) -> Pointer { - self.clone_multiple_to_other_heap(other, &[address]) + pub fn clone_single_to_other_heap_with_existing_mapping( + &self, + other: &mut Heap, + address: Pointer, + address_map: &mut HashMap, + ) -> Pointer { + self.clone_multiple_to_other_heap_with_existing_mapping(other, &[address], address_map) .pop() .unwrap() } + pub fn clone_multiple_to_other_heap( + &self, + other: &mut Heap, + addresses: &[Pointer], + ) -> Vec { + self.clone_multiple_to_other_heap_with_existing_mapping( + other, + addresses, + &mut HashMap::new(), + ) + } + pub fn clone_single_to_other_heap(&self, other: &mut Heap, address: Pointer) -> Pointer { + self.clone_single_to_other_heap_with_existing_mapping(other, address, &mut HashMap::new()) + } pub fn known_channels(&self) -> HashSet { let mut known = HashSet::new(); diff --git a/compiler/src/vm/mod.rs b/compiler/src/vm/mod.rs index 699006d7c..d70c0ac5e 100644 --- a/compiler/src/vm/mod.rs +++ b/compiler/src/vm/mod.rs @@ -7,15 +7,19 @@ pub mod tracer; mod use_module; use self::{ - channel::{ChannelBuf, Packet}, + channel::ChannelBuf, context::{ CombiningExecutionController, ExecutionController, RunLimitedNumberOfInstructions, UseProvider, }, heap::{ChannelId, SendPort}, + tracer::Tracer, +}; +pub use self::{ + channel::Packet, + fiber::Fiber, + heap::{Closure, Heap, Object, Pointer, Struct}, }; -pub use fiber::{Fiber, TearDownResult}; -pub use heap::{Closure, Heap, Object, Pointer, Struct}; use itertools::Itertools; use rand::seq::SliceRandom; use std::{ @@ -160,7 +164,7 @@ impl Vm { self.set_up_with_fiber(Fiber::new_for_running_module_closure(closure)) } - pub fn tear_down(mut self) -> TearDownResult { + pub fn tear_down(mut self) -> Result { let tree = self.fibers.remove(&self.root_fiber.unwrap()).unwrap(); let single = tree.into_single().unwrap(); single.fiber.tear_down() @@ -247,6 +251,7 @@ impl Vm { &mut self, use_provider: &mut U, execution_controller: &mut E, + tracer: &mut dyn Tracer, ) { while self.can_run() && execution_controller.should_continue_running() { self.run_raw( @@ -255,6 +260,7 @@ impl Vm { execution_controller, &mut RunLimitedNumberOfInstructions::new(100), ), + tracer, ); } } @@ -262,6 +268,7 @@ impl Vm { &mut self, use_provider: &mut U, execution_controller: &mut E, + tracer: &mut dyn Tracer, ) { assert!( self.can_run(), @@ -285,7 +292,8 @@ impl Vm { return; } - fiber.run(use_provider, execution_controller); + let mut tracer = tracer.in_fiber_tracer(fiber_id); + fiber.run(use_provider, execution_controller, &mut *tracer); let is_finished = match fiber.status() { fiber::Status::Running => false, @@ -385,7 +393,7 @@ impl Vm { .unwrap() .into_single() .unwrap(); - let TearDownResult { heap, result, .. } = single.fiber.tear_down(); + let result = single.fiber.tear_down(); let parent = single .parent .expect("we already checked we're not the root fiber"); @@ -398,14 +406,12 @@ impl Vm { match result { Ok(return_value) => { let is_finished = parallel.children.is_empty(); - let packet = Packet { - heap, - value: return_value, - }; match child { - ChildKind::InitialChild => parallel.return_value = Some(packet), + ChildKind::InitialChild => { + parallel.return_value = Some(return_value) + } ChildKind::SpawnedChild(return_channel) => { - self.send_to_channel(None, return_channel, packet) + self.send_to_channel(None, return_channel, return_value) } } @@ -419,9 +425,7 @@ impl Vm { FiberTree::Try(Try { .. }) => { self.fibers.replace(parent, |tree| { let mut paused_fiber = tree.into_try().unwrap().paused_fiber; - paused_fiber - .fiber - .complete_try(result.map(|value| Packet { heap, value })); + paused_fiber.fiber.complete_try(result); FiberTree::Single(paused_fiber) }); } @@ -564,8 +568,8 @@ impl Vm { } } fn parse_spawn_packet(packet: Packet) -> Option<(Heap, Pointer, ChannelId)> { - let Packet { mut heap, value } = packet; - let arguments: Struct = heap.get(value).data.clone().try_into().ok()?; + let Packet { mut heap, address } = packet; + let arguments: Struct = heap.get(address).data.clone().try_into().ok()?; let closure_symbol = heap.create_symbol("Closure".to_string()); let closure_address = arguments.get(&heap, closure_symbol)?; diff --git a/compiler/src/vm/tracer.rs b/compiler/src/vm/tracer.rs deleted file mode 100644 index 12a4ad666..000000000 --- a/compiler/src/vm/tracer.rs +++ /dev/null @@ -1,400 +0,0 @@ -use super::{heap::Pointer, Heap}; -use crate::{ - compiler::{ast_to_hir::AstToHir, cst::CstDb, hir::Id}, - database::Database, - language_server::utils::LspPositionConversion, - module::Module, -}; -use itertools::Itertools; -use std::time::Instant; -use tracing::error; - -#[derive(Clone)] -pub struct Tracer { - pub events: Vec, -} - -#[derive(Clone)] -pub struct Event { - pub when: Instant, - pub data: EventData, -} - -#[derive(Clone)] -pub enum EventData { - ValueEvaluated { - id: Id, - value: Pointer, - }, - CallStarted { - id: Id, - closure: Pointer, - args: Vec, - }, - CallEnded { - return_value: Pointer, - }, - NeedsStarted { - id: Id, - condition: Pointer, - reason: Pointer, - }, - NeedsEnded { - nothing: Pointer, - }, - ModuleStarted { - module: Module, - }, - ModuleEnded { - export_map: Pointer, - }, -} - -impl Tracer { - pub fn push(&mut self, data: EventData) { - self.events.push(Event { - when: Instant::now(), - data, - }); - } -} - -// Stack traces are a reduced view of the tracing state that represent the stack -// trace at a given moment in time. - -#[derive(Clone)] -pub enum StackEntry { - Call { - id: Id, - closure: Pointer, - args: Vec, - }, - Needs { - id: Id, - condition: Pointer, - reason: Pointer, - }, - Module { - module: Module, - }, -} - -impl Tracer { - pub fn new() -> Self { - Self { events: vec![] } - } - pub fn stack_trace(&self) -> Vec { - let mut stack = vec![]; - for Event { data, .. } in &self.events { - match data.clone() { - EventData::ValueEvaluated { .. } => {} - EventData::CallStarted { id, closure, args } => { - stack.push(StackEntry::Call { id, closure, args }) - } - EventData::CallEnded { .. } => { - stack.pop().unwrap(); - } - EventData::NeedsStarted { - id, - condition, - reason, - } => stack.push(StackEntry::Needs { - id, - condition, - reason, - }), - EventData::NeedsEnded { .. } => { - stack.pop().unwrap(); - } - EventData::ModuleStarted { module } => stack.push(StackEntry::Module { module }), - EventData::ModuleEnded { .. } => { - stack.pop().unwrap(); - } - } - } - stack - } - pub fn format_stack_trace(&self, db: &Database, heap: &Heap) -> String { - self.stack_trace() - .iter() - .rev() - .map(|entry| { - let (call_string, hir_id) = match entry { - StackEntry::Call { id, closure, args } => ( - format!( - "{closure} {}", - args.iter().map(|arg| arg.format(heap)).join(" ") - ), - Some(id), - ), - StackEntry::Needs { - id, - condition, - reason, - } => ( - format!("needs {} {}", condition.format(heap), reason.format(heap)), - Some(id), - ), - StackEntry::Module { module } => (format!("use {module}"), None), - }; - let caller_location_string = { - let (hir_id, ast_id, cst_id, span) = if let Some(hir_id) = hir_id { - let module = hir_id.module.clone(); - let ast_id = db.hir_to_ast_id(hir_id.clone()); - let cst_id = db.hir_to_cst_id(hir_id.clone()); - let cst = cst_id.map(|id| db.find_cst(module.clone(), id)); - let span = cst.map(|cst| { - ( - db.offset_to_lsp(module.clone(), cst.span.start), - db.offset_to_lsp(module.clone(), cst.span.end), - ) - }); - (Some(hir_id), ast_id, cst_id, span) - } else { - (None, None, None, None) - }; - format!( - "{}, {}, {}, {}", - hir_id - .map(|id| format!("{id}")) - .unwrap_or_else(|| "".to_string()), - ast_id - .map(|id| format!("{id}")) - .unwrap_or_else(|| "".to_string()), - cst_id - .map(|id| format!("{id}")) - .unwrap_or_else(|| "".to_string()), - span.map(|((start_line, start_col), (end_line, end_col))| format!( - "{}:{} – {}:{}", - start_line, start_col, end_line, end_col - )) - .unwrap_or_else(|| "".to_string()) - ) - }; - format!("{caller_location_string:90} {call_string}") - }) - .join("\n") - } - pub fn dump_stack_trace(&self, db: &Database, heap: &Heap) { - for line in self.format_stack_trace(db, heap).lines() { - error!("{}", line); - } - } -} - -// Full traces are a computed tree view of the whole execution. - -pub struct Trace { - #[allow(dead_code)] - start: Instant, - - #[allow(dead_code)] - end: Instant, - - data: TraceData, -} -pub enum TraceData { - Call { - id: Id, - closure: Pointer, - args: Vec, - inner: Vec, - result: TraceResult, - }, - Needs { - id: Id, - condition: Pointer, - reason: Pointer, - result: TraceResult, - }, - Module { - module: Module, - inner: Vec, - result: TraceResult, - }, -} -pub enum TraceResult { - Returned(Pointer), - - #[allow(dead_code)] - Panicked(Pointer), - - #[allow(dead_code)] - Canceled, -} - -impl Tracer { - pub fn full_trace(&self) -> Trace { - let mut stack = vec![Span { - start: self - .events - .first() - .map(|event| event.when) - .unwrap_or_else(Instant::now), - data: None, - inner: vec![], - }]; - for event in &self.events { - match &event.data { - EventData::ValueEvaluated { .. } => {} - EventData::CallStarted { id, closure, args } => { - stack.push(Span { - start: event.when, - data: Some(StackEntry::Call { - id: id.clone(), - closure: *closure, - args: args.clone(), - }), - inner: vec![], - }); - } - EventData::CallEnded { return_value } => { - let span = stack.pop().unwrap(); - let (id, closure, args) = match span.data.unwrap() { - StackEntry::Call { id, closure, args } => (id, closure, args), - _ => unreachable!(), - }; - stack.last_mut().unwrap().inner.push(Trace { - start: span.start, - end: event.when, - data: TraceData::Call { - id, - closure, - args, - inner: span.inner, - result: TraceResult::Returned(*return_value), - }, - }); - } - EventData::NeedsStarted { - id, - condition, - reason, - } => { - stack.push(Span { - start: event.when, - data: Some(StackEntry::Needs { - id: id.clone(), - condition: *condition, - reason: *reason, - }), - inner: vec![], - }); - } - EventData::NeedsEnded { nothing } => { - let span = stack.pop().unwrap(); - let (id, condition, reason) = match span.data.unwrap() { - StackEntry::Needs { - id, - condition, - reason, - } => (id, condition, reason), - _ => unreachable!(), - }; - stack.last_mut().unwrap().inner.push(Trace { - start: span.start, - end: event.when, - data: TraceData::Needs { - id, - condition, - reason, - result: TraceResult::Returned(*nothing), - }, - }); - } - EventData::ModuleStarted { module } => { - stack.push(Span { - start: event.when, - data: Some(StackEntry::Module { - module: module.clone(), - }), - inner: vec![], - }); - } - EventData::ModuleEnded { export_map } => { - let span = stack.pop().unwrap(); - let module = match span.data.unwrap() { - StackEntry::Module { module } => module, - _ => unreachable!(), - }; - stack.last_mut().unwrap().inner.push(Trace { - start: span.start, - end: event.when, - data: TraceData::Module { - module, - inner: span.inner, - result: TraceResult::Returned(*export_map), - }, - }); - } - } - } - stack.pop().unwrap().inner.pop().unwrap() // TODO: handle multiple traces - } -} - -struct Span { - start: Instant, - data: Option, - inner: Vec, -} - -impl TraceResult { - fn format(&self, heap: &Heap) -> String { - match self { - TraceResult::Returned(return_value) => return_value.format(heap), - TraceResult::Panicked(panic_value) => { - format!("panicked with {}", panic_value.format(heap)) - } - TraceResult::Canceled => "canceled".to_string(), - } - } -} - -impl Trace { - pub fn format(&self, heap: &Heap) -> String { - let mut lines = vec![]; - match &self.data { - TraceData::Call { - id, - args, - inner, - result, - .. - } => { - lines.push(format!( - "call {id} {} = {}", - args.iter().map(|arg| arg.format(heap)).join(" "), - result.format(heap), - )); - for trace in inner { - lines.extend(trace.format(heap).lines().map(|line| format!(" {line}"))); - } - } - TraceData::Needs { - condition, - reason, - result, - .. - } => { - lines.push(format!( - "needs {} {} = {}", - condition.format(heap), - reason.format(heap), - result.format(heap), - )); - } - TraceData::Module { - module, - inner, - result, - } => { - lines.push(format!("{module} = {}", result.format(heap))); - for trace in inner { - lines.extend(trace.format(heap).lines().map(|line| format!(" {line}"))); - } - } - } - lines.join("\n") - } -} diff --git a/compiler/src/vm/tracer/full_trace.rs b/compiler/src/vm/tracer/full_trace.rs new file mode 100644 index 000000000..d275fabe2 --- /dev/null +++ b/compiler/src/vm/tracer/full_trace.rs @@ -0,0 +1,201 @@ +use super::{ + super::heap::{ChannelId, Pointer}, + FiberId, Heap, +}; +use crate::{ + compiler::{ast_to_hir::AstToHir, cst::CstDb, hir::Id}, + database::Database, + language_server::utils::LspPositionConversion, + module::Module, +}; +use itertools::Itertools; +use std::{collections::HashMap, time::Instant}; +use tracing::error; + +// Full traces are a computed tree view of the whole execution. + +pub struct Trace { + #[allow(dead_code)] + start: Instant, + + #[allow(dead_code)] + end: Instant, + + data: TraceData, +} +pub enum TraceData { + Call { + id: Id, + closure: Pointer, + args: Vec, + inner: Vec, + result: TraceResult, + }, + Needs { + id: Id, + condition: Pointer, + reason: Pointer, + result: TraceResult, + }, + Module { + module: Module, + inner: Vec, + result: TraceResult, + }, +} +pub enum TraceResult { + Returned(Pointer), + + #[allow(dead_code)] + Panicked(Pointer), + + #[allow(dead_code)] + Canceled, +} + +impl FullTracer { + pub fn full_trace(&self) -> Trace { + let mut stacks: HashMap> = HashMap::new(); + for TimedEvent { when, event } in &self.events { + match &event { + Event::FiberCreated { fiber } => { + stacks.insert( + *fiber, + vec![Span { + start: when.clone(), + data: None, + inner: vec![], + }], + ); + } + Event::InFiber { fiber, event } => { + let stack = stacks.get_mut(fiber).unwrap(); + match event { + InFiberEvent::ModuleStarted { module } => todo!(), + InFiberEvent::ModuleEnded { export_map } => todo!(), + InFiberEvent::CallStarted { id, closure, args } => stack.push(Span { + start: when, + data: Some(StackEntry::Call { + id: id.clone(), + closure: *closure, + args: args.clone(), + }), + inner: vec![], + }), + InFiberEvent::CallEnded { return_value } => { + let span = stack.pop().unwrap(); + let (id, closure, args) = match span.data.unwrap() { + StackEntry::Call { id, closure, args } => (id, closure, args), + _ => unreachable!(), + }; + stack.last_mut().unwrap().inner.push(Trace { + start: span.start, + end: event.when, + data: TraceData::Call { + id, + closure, + args, + inner: span.inner, + result: TraceResult::Returned(*return_value), + }, + }); + } + InFiberEvent::ModuleStarted { module } => { + stack.push(Span { + start: event.when, + data: Some(StackEntry::Module { + module: module.clone(), + }), + inner: vec![], + }); + } + InFiberEvent::ModuleEnded { export_map } => { + let span = stack.pop().unwrap(); + let module = match span.data.unwrap() { + StackEntry::Module { module } => module, + _ => unreachable!(), + }; + stack.last_mut().unwrap().inner.push(Trace { + start: span.start, + end: event.when, + data: TraceData::Module { + module, + inner: span.inner, + result: TraceResult::Returned(*export_map), + }, + }); + } + _ => {} + } + } + } + } + stacks + } +} + +struct Span { + start: Instant, + data: Option, + inner: Vec, +} + +impl TraceResult { + fn format(&self, heap: &Heap) -> String { + match self { + TraceResult::Returned(return_value) => return_value.format(heap), + TraceResult::Panicked(panic_value) => { + format!("panicked with {}", panic_value.format(heap)) + } + TraceResult::Canceled => "canceled".to_string(), + } + } +} + +impl Trace { + pub fn format(&self, heap: &Heap) -> String { + let mut lines = vec![]; + match &self.data { + TraceData::Call { + id, + args, + inner, + result, + .. + } => { + lines.push(format!( + "call {id} {} = {}", + args.iter().map(|arg| arg.format(heap)).join(" "), + result.format(heap), + )); + for trace in inner { + lines.extend(trace.format(heap).lines().map(|line| format!(" {line}"))); + } + } + TraceData::Needs { + condition, + reason, + result, + .. + } => { + lines.push(format!( + "needs {} {} = {}", + condition.format(heap), + reason.format(heap), + result.format(heap), + )); + } + TraceData::Module { + module, + inner, + result, + } => { + lines.push(format!("{module} = {}", result.format(heap))); + for trace in inner { + lines.extend(trace.format(heap).lines().map(|line| format!(" {line}"))); + } + } + } + lines.join("\n") + } +} diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs new file mode 100644 index 000000000..b4d427198 --- /dev/null +++ b/compiler/src/vm/tracer/mod.rs @@ -0,0 +1,225 @@ +// mod full_trace; +pub mod stack_trace; + +use super::{ + heap::{ChannelId, Pointer}, + FiberId, Heap, +}; +use crate::{compiler::hir::Id, module::Module}; +use std::{collections::HashMap, time::Instant}; + +pub trait Tracer { + fn fiber_execution_started(&mut self, fiber: FiberId); + fn fiber_execution_ended(&mut self, fiber: FiberId); + fn sent_to_channel(&mut self, value: Pointer, from: FiberId, to: ChannelId); + fn received_from_channel(&mut self, value: Pointer, from: ChannelId, to: FiberId); + + fn in_fiber_tracer<'a>(&'a mut self, fiber: FiberId) -> Box + 'a> + where + Self: 'a; +} + +pub trait InFiberTracer<'a> { + fn module_started(&mut self, module: Module); + fn module_ended(&mut self, heap: &Heap, export_map: Pointer); + fn value_evaluated(&mut self, heap: &Heap, id: Id, value: Pointer); + fn found_fuzzable_closure(&mut self, heap: &Heap, id: Id, closure: Pointer); + fn call_started(&mut self, heap: &Heap, id: Id, closure: Pointer, args: Vec); + fn call_ended(&mut self, heap: &Heap, return_value: Pointer); +} + +// A dummy version of the tracer that is used when running known instructions +// without wanting to trace them. + +pub struct DummyTracer; +pub struct DummyInFiberTracer; +impl Tracer for DummyTracer { + fn fiber_execution_started(&mut self, _fiber: FiberId) {} + fn fiber_execution_ended(&mut self, _fiber: FiberId) {} + fn sent_to_channel(&mut self, _value: Pointer, _from: FiberId, _to: ChannelId) {} + fn received_from_channel(&mut self, _value: Pointer, _from: ChannelId, _to: FiberId) {} + + fn in_fiber_tracer<'a>(&'a mut self, _fiber: FiberId) -> Box> + where + Self: 'a, + { + Box::new(DummyInFiberTracer) + } +} +impl<'a> InFiberTracer<'a> for DummyInFiberTracer { + fn module_started(&mut self, _module: Module) {} + fn module_ended(&mut self, _heap: &Heap, _export_map: Pointer) {} + fn value_evaluated(&mut self, _heap: &Heap, _id: Id, _value: Pointer) {} + fn found_fuzzable_closure(&mut self, _heap: &Heap, _id: Id, _closure: Pointer) {} + fn call_started(&mut self, _heap: &Heap, _id: Id, _closure: Pointer, _args: Vec) {} + fn call_ended(&mut self, _heap: &Heap, _return_value: Pointer) {} +} + +// A full tracer that saves all events that occur with timestamps. + +#[derive(Clone)] +pub struct FullTracer { + pub events: Vec, + heap: Heap, + transferred_objects: HashMap>, +} +#[derive(Clone)] +pub struct TimedEvent { + when: Instant, + event: Event, +} +#[derive(Clone)] +pub enum Event { + FiberCreated { + fiber: FiberId, + }, + FiberDone { + fiber: FiberId, + }, + FiberPanicked { + fiber: FiberId, + }, + FiberCanceled { + fiber: FiberId, + }, + FiberExecutionStarted { + fiber: FiberId, + }, + FiberExecutionEnded { + fiber: FiberId, + }, + ChannelCreated { + channel: ChannelId, + }, + SentToChannel { + value: Pointer, + from: FiberId, + to: ChannelId, + }, + ReceivedFromChannel { + value: Pointer, + from: ChannelId, + to: FiberId, + }, + InFiber { + fiber: FiberId, + event: InFiberEvent, + }, +} +#[derive(Clone)] +pub enum InFiberEvent { + ModuleStarted { + module: Module, + }, + ModuleEnded { + export_map: Pointer, + }, + ValueEvaluated { + id: Id, + value: Pointer, + }, + FoundFuzzableClosure { + id: Id, + closure: Pointer, + }, + CallStarted { + id: Id, + closure: Pointer, + args: Vec, + }, + CallEnded { + return_value: Pointer, + }, +} + +impl FullTracer { + pub fn new() -> Self { + Self { + events: vec![], + heap: Heap::default(), + transferred_objects: HashMap::new(), + } + } + fn push(&mut self, data: Event) { + self.events.push(TimedEvent { + when: Instant::now(), + event: data, + }); + } + fn import_from_fiber_heap(&mut self, fiber: FiberId, heap: &Heap, value: Pointer) -> Pointer { + let address_map = self + .transferred_objects + .entry(fiber) + .or_insert_with(|| HashMap::new()); + heap.clone_single_to_other_heap_with_existing_mapping(&mut self.heap, value, address_map) + } +} +impl Tracer for FullTracer { + fn fiber_execution_started(&mut self, fiber: FiberId) { + self.push(Event::FiberExecutionStarted { fiber }); + } + fn fiber_execution_ended(&mut self, fiber: FiberId) { + self.push(Event::FiberExecutionEnded { fiber }); + } + fn sent_to_channel(&mut self, value: Pointer, from: FiberId, to: ChannelId) { + self.push(Event::SentToChannel { value, from, to }); + } + fn received_from_channel(&mut self, value: Pointer, from: ChannelId, to: FiberId) { + self.push(Event::ReceivedFromChannel { value, from, to }); + } + + fn in_fiber_tracer<'a>(&'a mut self, fiber: FiberId) -> Box + 'a> + where + Self: 'a, + { + Box::new(FullInFiberTracer { + tracer: self, + fiber, + }) + } +} + +pub struct FullInFiberTracer<'a> { + tracer: &'a mut FullTracer, + fiber: FiberId, +} +impl<'a> FullInFiberTracer<'a> { + fn import_from_fiber_heap(&mut self, heap: &Heap, value: Pointer) -> Pointer { + self.tracer.import_from_fiber_heap(self.fiber, heap, value) + } + fn push(&mut self, event: InFiberEvent) { + self.tracer.push(Event::InFiber { + fiber: self.fiber, + event, + }); + } +} +impl<'a> InFiberTracer<'a> for FullInFiberTracer<'a> { + fn module_started(&mut self, module: Module) { + self.push(InFiberEvent::ModuleStarted { module }); + } + fn module_ended(&mut self, heap: &Heap, export_map: Pointer) { + let export_map = self.import_from_fiber_heap(heap, export_map); + self.push(InFiberEvent::ModuleEnded { export_map }); + } + fn value_evaluated(&mut self, heap: &Heap, id: Id, value: Pointer) { + let value = self.import_from_fiber_heap(heap, value); + self.push(InFiberEvent::ValueEvaluated { id, value }); + } + fn found_fuzzable_closure(&mut self, heap: &Heap, id: Id, closure: Pointer) { + let closure = self.import_from_fiber_heap(heap, closure); + self.push(InFiberEvent::FoundFuzzableClosure { id, closure }); + } + fn call_started(&mut self, heap: &Heap, id: Id, closure: Pointer, args: Vec) { + let closure = self.import_from_fiber_heap(heap, closure); + let args = args + .into_iter() + .map(|arg| self.import_from_fiber_heap(heap, arg)) + .collect(); + self.push(InFiberEvent::CallStarted { id, closure, args }); + } + fn call_ended(&mut self, heap: &Heap, return_value: Pointer) { + let return_value = self.import_from_fiber_heap(heap, return_value); + self.push(InFiberEvent::CallEnded { return_value }); + } +} diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs new file mode 100644 index 000000000..5a69662b1 --- /dev/null +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -0,0 +1,131 @@ +use super::{super::heap::Pointer, Event, FiberId, FullTracer, Heap, InFiberEvent}; +use crate::{ + compiler::{ast_to_hir::AstToHir, cst::CstDb, hir::Id}, + database::Database, + language_server::utils::LspPositionConversion, + module::Module, +}; +use itertools::Itertools; +use std::collections::HashMap; +use tracing::error; + +// Stack traces are a reduced view of the tracing state that represent the stack +// trace at a given moment in time. + +#[derive(Clone)] +pub enum StackEntry { + Call { + id: Id, + closure: Pointer, + args: Vec, + }, + Needs { + id: Id, + condition: Pointer, + reason: Pointer, + }, + Module { + module: Module, + }, +} + +impl FullTracer { + pub fn stack_traces(&self) -> HashMap> { + let mut stacks: HashMap> = HashMap::new(); + for timed_event in &self.events { + if let Event::InFiber { fiber, event } = &timed_event.event { + let stack = stacks.entry(*fiber).or_default(); + match event { + InFiberEvent::CallStarted { id, closure, args } => { + stack.push(StackEntry::Call { + id: id.clone(), + closure: closure.clone(), + args: args.clone(), + }); + } + InFiberEvent::CallEnded { .. } => { + stack.pop().unwrap(); + } + InFiberEvent::ModuleStarted { module } => { + stack.push(StackEntry::Module { + module: module.clone(), + }); + } + InFiberEvent::ModuleEnded { .. } => { + stack.pop().unwrap(); + } + _ => {} + } + } + } + stacks + } + pub fn format_stack_traces(&self, db: &Database, heap: &Heap) -> String { + let mut lines = vec![]; + + for (fiber, stack) in self.stack_traces() { + lines.push(format!("{fiber:?}:")); + for entry in stack.iter().rev() { + let (call_string, hir_id) = match entry { + StackEntry::Call { id, closure, args } => ( + format!( + "{closure} {}", + args.iter().map(|arg| arg.format(heap)).join(" ") + ), + Some(id), + ), + StackEntry::Needs { + id, + condition, + reason, + } => ( + format!("needs {} {}", condition.format(heap), reason.format(heap)), + Some(id), + ), + StackEntry::Module { module } => (format!("use {module}"), None), + }; + let caller_location_string = { + let (hir_id, ast_id, cst_id, span) = if let Some(hir_id) = hir_id { + let module = hir_id.module.clone(); + let ast_id = db.hir_to_ast_id(hir_id.clone()); + let cst_id = db.hir_to_cst_id(hir_id.clone()); + let cst = cst_id.map(|id| db.find_cst(module.clone(), id)); + let span = cst.map(|cst| { + ( + db.offset_to_lsp(module.clone(), cst.span.start), + db.offset_to_lsp(module.clone(), cst.span.end), + ) + }); + (Some(hir_id), ast_id, cst_id, span) + } else { + (None, None, None, None) + }; + format!( + "{}, {}, {}, {}", + hir_id + .map(|id| format!("{id}")) + .unwrap_or_else(|| "".to_string()), + ast_id + .map(|id| format!("{id}")) + .unwrap_or_else(|| "".to_string()), + cst_id + .map(|id| format!("{id}")) + .unwrap_or_else(|| "".to_string()), + span.map(|((start_line, start_col), (end_line, end_col))| format!( + "{}:{} – {}:{}", + start_line, start_col, end_line, end_col + )) + .unwrap_or_else(|| "".to_string()) + ) + }; + lines.push(format!("{caller_location_string:90} {call_string}")); + } + } + lines.join("\n") + } + pub fn dump_stack_traces(&self, db: &Database, heap: &Heap) { + for line in self.format_stack_traces(db, heap).lines() { + error!("{}", line); + } + } +} diff --git a/compiler/src/vm/use_module.rs b/compiler/src/vm/use_module.rs index 339e82bc1..5dc670ef5 100644 --- a/compiler/src/vm/use_module.rs +++ b/compiler/src/vm/use_module.rs @@ -1,6 +1,7 @@ use super::{ context::{PanickingUseProvider, UseProvider, UseResult}, heap::{Closure, Heap, Pointer, Text}, + tracer::DummyInFiberTracer, Fiber, }; use crate::{ @@ -10,9 +11,9 @@ use crate::{ use itertools::Itertools; impl Fiber { - pub fn use_module( + pub fn use_module( &mut self, - use_provider: &U, + use_provider: &mut dyn UseProvider, current_module: Module, relative_path: Pointer, ) -> Result<(), String> { @@ -32,7 +33,11 @@ impl Fiber { let module_closure = Closure::of_module_lir(module, lir); let address = self.heap.create_closure(module_closure); self.data_stack.push(address); - self.run_instruction(&PanickingUseProvider, Instruction::Call { num_args: 0 }); + self.run_instruction( + &mut PanickingUseProvider, + &mut DummyInFiberTracer, + Instruction::Call { num_args: 0 }, + ); } } From 2bf40123a7b295d391d42a60667249a7f3fa3096 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Tue, 4 Oct 2022 21:45:47 +0200 Subject: [PATCH 02/44] Display stack traces --- compiler/src/main.rs | 14 ++++++++------ compiler/src/vm/tracer/stack_trace.rs | 14 +++++++++----- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/compiler/src/main.rs b/compiler/src/main.rs index 6d96521c2..5e1e5668f 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -28,8 +28,8 @@ use crate::{ language_server::utils::LspPositionConversion, module::{Module, ModuleKind}, vm::{ - context::{DbUseProvider, RunForever}, - tracer::DummyTracer, + context::{DbUseProvider, RunForever, RunLimitedNumberOfInstructions}, + tracer::{DummyTracer, FullTracer}, Closure, Status, Struct, Vm, }, }; @@ -207,6 +207,9 @@ fn run(options: CandyRunOptions) { let path_string = options.file.to_string_lossy(); info!("Running `{path_string}`."); + + let mut tracer = FullTracer::new(); + let mut vm = Vm::new(); vm.set_up_for_running_module_closure(module_closure); loop { @@ -216,8 +219,8 @@ fn run(options: CandyRunOptions) { debug!("VM still running."); vm.run( &mut DbUseProvider { db: &db }, - &mut RunForever, - &mut DummyTracer, + &mut RunLimitedNumberOfInstructions::new(100), + &mut tracer, ); } Status::WaitingForOperations => { @@ -249,8 +252,7 @@ fn run(options: CandyRunOptions) { Err(reason) => { error!("The module panicked because {reason}."); error!("This is the stack trace:"); - // tracer.dump_stack_trace(&db, &heap); - todo!(); + tracer.dump_stack_traces(&db); return; } }; diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs index 5a69662b1..ecb57e9cb 100644 --- a/compiler/src/vm/tracer/stack_trace.rs +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -60,7 +60,7 @@ impl FullTracer { } stacks } - pub fn format_stack_traces(&self, db: &Database, heap: &Heap) -> String { + pub fn format_stack_traces(&self, db: &Database) -> String { let mut lines = vec![]; for (fiber, stack) in self.stack_traces() { @@ -70,7 +70,7 @@ impl FullTracer { StackEntry::Call { id, closure, args } => ( format!( "{closure} {}", - args.iter().map(|arg| arg.format(heap)).join(" ") + args.iter().map(|arg| arg.format(&self.heap)).join(" ") ), Some(id), ), @@ -79,7 +79,11 @@ impl FullTracer { condition, reason, } => ( - format!("needs {} {}", condition.format(heap), reason.format(heap)), + format!( + "needs {} {}", + condition.format(&self.heap), + reason.format(&self.heap) + ), Some(id), ), StackEntry::Module { module } => (format!("use {module}"), None), @@ -123,8 +127,8 @@ impl FullTracer { } lines.join("\n") } - pub fn dump_stack_traces(&self, db: &Database, heap: &Heap) { - for line in self.format_stack_traces(db, heap).lines() { + pub fn dump_stack_traces(&self, db: &Database) { + for line in self.format_stack_traces(db).lines() { error!("{}", line); } } From c7499baeddbaa04108ecc7cdb28a9ce86ea1a9bd Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Tue, 4 Oct 2022 21:46:01 +0200 Subject: [PATCH 03/44] Make cloning to other heap cheaper --- compiler/src/vm/heap/mod.rs | 49 +++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/compiler/src/vm/heap/mod.rs b/compiler/src/vm/heap/mod.rs index 01494d5fd..368866f28 100644 --- a/compiler/src/vm/heap/mod.rs +++ b/compiler/src/vm/heap/mod.rs @@ -135,25 +135,26 @@ impl Heap { addresses: &[Pointer], address_map: &mut HashMap, ) -> Vec { - let mut objects_to_refcounts = HashMap::new(); + let mut additional_refcounts = HashMap::new(); for address in addresses { - self.gather_objects_to_clone(&mut objects_to_refcounts, *address); + self.prepare_object_cloning(address_map, &mut additional_refcounts, other, *address); } - for object in objects_to_refcounts.keys() { + for object in additional_refcounts.keys() { address_map .entry(*object) .or_insert_with(|| other.reserve_address()); } - for (address, refcount) in objects_to_refcounts { - other.objects.insert( - address_map[&address], - Object { - reference_count: refcount, + for (address, refcount) in additional_refcounts { + other + .objects + .entry(address_map[&address]) + .or_insert_with(|| Object { + reference_count: 0, data: Self::map_data(address_map, &self.get(address).data), - }, - ); + }) + .reference_count += refcount; } addresses @@ -161,14 +162,21 @@ impl Heap { .map(|address| address_map[address]) .collect() } - fn gather_objects_to_clone( + fn prepare_object_cloning( &self, - objects_to_refcounts: &mut HashMap, + address_map: &mut HashMap, + additional_refcounts: &mut HashMap, + other: &mut Heap, address: Pointer, ) { - *objects_to_refcounts.entry(address).or_default() += 1; - for child in self.get(address).children() { - self.gather_objects_to_clone(objects_to_refcounts, child); + *additional_refcounts.entry(address).or_default() += 1; + + let is_new = !address_map.contains_key(&address); + if is_new { + address_map.insert(address, other.reserve_address()); + for child in self.get(address).children() { + self.prepare_object_cloning(address_map, additional_refcounts, other, child); + } } } fn map_data(address_map: &HashMap, data: &Data) -> Data { @@ -207,17 +215,6 @@ impl Heap { .pop() .unwrap() } - pub fn clone_multiple_to_other_heap( - &self, - other: &mut Heap, - addresses: &[Pointer], - ) -> Vec { - self.clone_multiple_to_other_heap_with_existing_mapping( - other, - addresses, - &mut HashMap::new(), - ) - } pub fn clone_single_to_other_heap(&self, other: &mut Heap, address: Pointer) -> Pointer { self.clone_single_to_other_heap_with_existing_mapping(other, address, &mut HashMap::new()) } From 475ec6dc99d6510798c0abd54e4c30fb83aba228 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Tue, 4 Oct 2022 22:57:11 +0200 Subject: [PATCH 04/44] Improve stack trace formatting --- compiler/src/main.rs | 15 +-- compiler/src/vm/tracer/stack_trace.rs | 131 ++++++++++++++------------ 2 files changed, 81 insertions(+), 65 deletions(-) diff --git a/compiler/src/main.rs b/compiler/src/main.rs index 5e1e5668f..ea6c19927 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -219,7 +219,7 @@ fn run(options: CandyRunOptions) { debug!("VM still running."); vm.run( &mut DbUseProvider { db: &db }, - &mut RunLimitedNumberOfInstructions::new(100), + &mut RunLimitedNumberOfInstructions::new(100000), &mut tracer, ); } @@ -251,8 +251,10 @@ fn run(options: CandyRunOptions) { } Err(reason) => { error!("The module panicked because {reason}."); - error!("This is the stack trace:"); - tracer.dump_stack_traces(&db); + error!( + "This is the stack trace:\n{}", + tracer.format_stack_traces(&db) + ); return; } }; @@ -318,9 +320,10 @@ fn run(options: CandyRunOptions) { Ok(return_value) => info!("The main function returned: {return_value:?}"), Err(reason) => { error!("The main function panicked because {reason}."); - error!("This is the stack trace:"); - // tracer.dump_stack_trace(&db, &heap); - todo!(); + error!( + "This is the stack trace:\n{}", + tracer.format_stack_traces(&db) + ); } } } diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs index ecb57e9cb..a70d12fc3 100644 --- a/compiler/src/vm/tracer/stack_trace.rs +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -1,13 +1,16 @@ -use super::{super::heap::Pointer, Event, FiberId, FullTracer, Heap, InFiberEvent}; +use super::{super::heap::Pointer, Event, FiberId, FullTracer, InFiberEvent}; use crate::{ - compiler::{ast_to_hir::AstToHir, cst::CstDb, hir::Id}, + compiler::{ + ast_to_hir::AstToHir, + cst::{Cst, CstDb, CstKind}, + hir::Id, + }, database::Database, language_server::utils::LspPositionConversion, module::Module, }; use itertools::Itertools; use std::collections::HashMap; -use tracing::error; // Stack traces are a reduced view of the tracing state that represent the stack // trace at a given moment in time. @@ -39,7 +42,7 @@ impl FullTracer { InFiberEvent::CallStarted { id, closure, args } => { stack.push(StackEntry::Call { id: id.clone(), - closure: closure.clone(), + closure: *closure, args: args.clone(), }); } @@ -66,70 +69,80 @@ impl FullTracer { for (fiber, stack) in self.stack_traces() { lines.push(format!("{fiber:?}:")); for entry in stack.iter().rev() { - let (call_string, hir_id) = match entry { - StackEntry::Call { id, closure, args } => ( - format!( - "{closure} {}", - args.iter().map(|arg| arg.format(&self.heap)).join(" ") - ), - Some(id), + let hir_id = match entry { + StackEntry::Call { id, .. } => Some(id), + StackEntry::Needs { id, .. } => Some(id), + StackEntry::Module { .. } => None, + }; + let (cst_id, span) = if let Some(hir_id) = hir_id { + let module = hir_id.module.clone(); + let cst_id = db.hir_to_cst_id(hir_id.clone()); + let cst = cst_id.map(|id| db.find_cst(module.clone(), id)); + let span = cst.map(|cst| { + ( + db.offset_to_lsp(module.clone(), cst.span.start), + db.offset_to_lsp(module.clone(), cst.span.end), + ) + }); + (cst_id, span) + } else { + (None, None) + }; + let caller_location_string = format!( + "{} {}", + hir_id + .map(|id| format!("{id}")) + .unwrap_or_else(|| "".to_string()), + span.map(|((start_line, start_col), (end_line, end_col))| format!( + "{}:{} – {}:{}", + start_line, start_col, end_line, end_col + )) + .unwrap_or_else(|| "".to_string()) + ); + let call_string = match entry { + StackEntry::Call { closure, args, .. } => format!( + "{} {}", + cst_id + .and_then(|id| { + let cst = db.find_cst(hir_id.unwrap().module.clone(), id); + match cst.kind { + CstKind::Call { receiver, .. } => { + receiver.extract_receiver_name() + } + _ => None, + } + }) + .unwrap_or_else(|| closure.format(&self.heap)), + args.iter().map(|arg| arg.format(&self.heap)).join(" ") ), StackEntry::Needs { - id, - condition, - reason, - } => ( - format!( - "needs {} {}", - condition.format(&self.heap), - reason.format(&self.heap) - ), - Some(id), + condition, reason, .. + } => format!( + "needs {} {}", + condition.format(&self.heap), + reason.format(&self.heap), ), - StackEntry::Module { module } => (format!("use {module}"), None), - }; - let caller_location_string = { - let (hir_id, ast_id, cst_id, span) = if let Some(hir_id) = hir_id { - let module = hir_id.module.clone(); - let ast_id = db.hir_to_ast_id(hir_id.clone()); - let cst_id = db.hir_to_cst_id(hir_id.clone()); - let cst = cst_id.map(|id| db.find_cst(module.clone(), id)); - let span = cst.map(|cst| { - ( - db.offset_to_lsp(module.clone(), cst.span.start), - db.offset_to_lsp(module.clone(), cst.span.end), - ) - }); - (Some(hir_id), ast_id, cst_id, span) - } else { - (None, None, None, None) - }; - format!( - "{}, {}, {}, {}", - hir_id - .map(|id| format!("{id}")) - .unwrap_or_else(|| "".to_string()), - ast_id - .map(|id| format!("{id}")) - .unwrap_or_else(|| "".to_string()), - cst_id - .map(|id| format!("{id}")) - .unwrap_or_else(|| "".to_string()), - span.map(|((start_line, start_col), (end_line, end_col))| format!( - "{}:{} – {}:{}", - start_line, start_col, end_line, end_col - )) - .unwrap_or_else(|| "".to_string()) - ) + StackEntry::Module { module } => format!("module {module}"), }; lines.push(format!("{caller_location_string:90} {call_string}")); } } lines.join("\n") } - pub fn dump_stack_traces(&self, db: &Database) { - for line in self.format_stack_traces(db).lines() { - error!("{}", line); +} + +impl Cst { + fn extract_receiver_name(&self) -> Option { + match &self.kind { + CstKind::TrailingWhitespace { child, .. } => child.extract_receiver_name(), + CstKind::Identifier(identifier) => Some(identifier.to_string()), + CstKind::Parenthesized { inner, .. } => inner.extract_receiver_name(), + CstKind::StructAccess { struct_, key, .. } => { + let struct_string = struct_.extract_receiver_name()?; + let key = key.extract_receiver_name()?; + Some(format!("{struct_string}.{key}")) + } + _ => None, } } } From 9a25969ea8f0d84ff735f3d9940c66cf4d633282 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Tue, 4 Oct 2022 23:09:16 +0200 Subject: [PATCH 05/44] Trace needs --- compiler/src/vm/fiber.rs | 10 ++-------- compiler/src/vm/tracer/mod.rs | 22 ++++++++++++++++++++++ compiler/src/vm/tracer/stack_trace.rs | 22 ++++++++++++++++++---- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index ab00f1460..2d1557618 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -420,18 +420,12 @@ impl Fiber { let reason = self.data_stack[self.data_stack.len() - 1]; self.heap.dup(condition); self.heap.dup(reason); - // TODO: Trace or remove this after fault analysis works. - // self.tracer.push(EventData::NeedsStarted { - // id, - // condition, - // reason, - // }); + tracer.needs_started(&self.heap, id, condition, reason); } Instruction::TraceNeedsEnds => { let nothing = *self.data_stack.last().unwrap(); self.heap.dup(nothing); - // TODO: Trace or remove this after fault analysis works. - // self.tracer.push(EventData::NeedsEnded { nothing }); + tracer.needs_ended(); } Instruction::TraceModuleStarts { module } => { if self.import_stack.contains(&module) { diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index b4d427198..e8489a617 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -26,6 +26,8 @@ pub trait InFiberTracer<'a> { fn found_fuzzable_closure(&mut self, heap: &Heap, id: Id, closure: Pointer); fn call_started(&mut self, heap: &Heap, id: Id, closure: Pointer, args: Vec); fn call_ended(&mut self, heap: &Heap, return_value: Pointer); + fn needs_started(&mut self, heap: &Heap, id: Id, condition: Pointer, reason: Pointer); + fn needs_ended(&mut self); } // A dummy version of the tracer that is used when running known instructions @@ -53,6 +55,8 @@ impl<'a> InFiberTracer<'a> for DummyInFiberTracer { fn found_fuzzable_closure(&mut self, _heap: &Heap, _id: Id, _closure: Pointer) {} fn call_started(&mut self, _heap: &Heap, _id: Id, _closure: Pointer, _args: Vec) {} fn call_ended(&mut self, _heap: &Heap, _return_value: Pointer) {} + fn needs_started(&mut self, _heap: &Heap, _id: Id, _condition: Pointer, _reason: Pointer) {} + fn needs_ended(&mut self) {} } // A full tracer that saves all events that occur with timestamps. @@ -130,6 +134,12 @@ pub enum InFiberEvent { CallEnded { return_value: Pointer, }, + NeedsStarted { + id: Id, + condition: Pointer, + reason: Pointer, + }, + NeedsEnded, } impl FullTracer { @@ -222,4 +232,16 @@ impl<'a> InFiberTracer<'a> for FullInFiberTracer<'a> { let return_value = self.import_from_fiber_heap(heap, return_value); self.push(InFiberEvent::CallEnded { return_value }); } + fn needs_started(&mut self, heap: &Heap, id: Id, condition: Pointer, reason: Pointer) { + let condition = self.import_from_fiber_heap(heap, condition); + let reason = self.import_from_fiber_heap(heap, reason); + self.push(InFiberEvent::NeedsStarted { + id, + condition, + reason, + }); + } + fn needs_ended(&mut self) { + self.push(InFiberEvent::NeedsEnded); + } } diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs index a70d12fc3..6563a0ef6 100644 --- a/compiler/src/vm/tracer/stack_trace.rs +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -39,6 +39,14 @@ impl FullTracer { if let Event::InFiber { fiber, event } = &timed_event.event { let stack = stacks.entry(*fiber).or_default(); match event { + InFiberEvent::ModuleStarted { module } => { + stack.push(StackEntry::Module { + module: module.clone(), + }); + } + InFiberEvent::ModuleEnded { .. } => { + stack.pop().unwrap(); + } InFiberEvent::CallStarted { id, closure, args } => { stack.push(StackEntry::Call { id: id.clone(), @@ -49,12 +57,18 @@ impl FullTracer { InFiberEvent::CallEnded { .. } => { stack.pop().unwrap(); } - InFiberEvent::ModuleStarted { module } => { - stack.push(StackEntry::Module { - module: module.clone(), + InFiberEvent::NeedsStarted { + id, + condition, + reason, + } => { + stack.push(StackEntry::Needs { + id: id.clone(), + condition: *condition, + reason: *reason, }); } - InFiberEvent::ModuleEnded { .. } => { + InFiberEvent::NeedsEnded => { stack.pop().unwrap(); } _ => {} From 80870552ebbbc0595c36f1f0db2a775865f5b17f Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Wed, 5 Oct 2022 13:56:27 +0200 Subject: [PATCH 06/44] Format stack traces spanning multiple fibers --- compiler/src/main.rs | 7 +- compiler/src/vm/mod.rs | 81 +++++++++------ compiler/src/vm/tracer/mod.rs | 104 ++++++++++++++++++- compiler/src/vm/tracer/stack_trace.rs | 142 +++++++++++++++----------- 4 files changed, 237 insertions(+), 97 deletions(-) diff --git a/compiler/src/main.rs b/compiler/src/main.rs index ea6c19927..1fded3130 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -233,8 +233,7 @@ fn run(options: CandyRunOptions) { let result = vm.tear_down(); if options.debug { - todo!(); - // module.dump_associated_debug_file("trace", &tracer.full_trace().format(&heap)); + module.dump_associated_debug_file("trace", &format!("{tracer:?}")); } let (mut heap, exported_definitions): (_, Struct) = match result { @@ -253,7 +252,7 @@ fn run(options: CandyRunOptions) { error!("The module panicked because {reason}."); error!( "This is the stack trace:\n{}", - tracer.format_stack_traces(&db) + tracer.format_panic_stack_trace_to_root_fiber(&db) ); return; } @@ -322,7 +321,7 @@ fn run(options: CandyRunOptions) { error!("The main function panicked because {reason}."); error!( "This is the stack trace:\n{}", - tracer.format_stack_traces(&db) + tracer.format_panic_stack_trace_to_root_fiber(&db) ); } } diff --git a/compiler/src/vm/mod.rs b/compiler/src/vm/mod.rs index d70c0ac5e..51b914b03 100644 --- a/compiler/src/vm/mod.rs +++ b/compiler/src/vm/mod.rs @@ -36,7 +36,6 @@ use tracing::{info, warn}; #[derive(Clone)] pub struct Vm { fibers: HashMap, - root_fiber: Option, // only None when no fiber is created yet channels: HashMap, pub external_operations: HashMap>, @@ -128,29 +127,35 @@ pub enum Status { Panicked { reason: String }, } +impl FiberId { + pub fn root() -> Self { + 0.into() + } +} + impl Vm { pub fn new() -> Self { Self { channels: Default::default(), fibers: HashMap::new(), - root_fiber: None, external_operations: Default::default(), channel_id_generator: IdGenerator::start_at(0), - fiber_id_generator: IdGenerator::start_at(0), + fiber_id_generator: IdGenerator::start_at(FiberId::root().0 + 1), } } fn set_up_with_fiber(&mut self, fiber: Fiber) { - assert!(self.root_fiber.is_none(), "VM already set up"); - let root_fiber_id = self.fiber_id_generator.generate(); + assert!( + !self.fibers.contains_key(&FiberId::root()), + "already set up" + ); self.fibers.insert( - root_fiber_id, + FiberId::root(), FiberTree::Single(Single { fiber, parent: None, }), ); - self.root_fiber = Some(root_fiber_id); } pub fn set_up_for_running_closure( &mut self, @@ -165,13 +170,13 @@ impl Vm { } pub fn tear_down(mut self) -> Result { - let tree = self.fibers.remove(&self.root_fiber.unwrap()).unwrap(); + let tree = self.fibers.remove(&FiberId::root()).unwrap(); let single = tree.into_single().unwrap(); single.fiber.tear_down() } pub fn status(&self) -> Status { - self.status_of(self.root_fiber.expect("VM not set up yet")) + self.status_of(FiberId::root()) } fn status_of(&self, fiber: FiberId) -> Status { match &self.fibers[&fiber] { @@ -208,15 +213,6 @@ impl Vm { matches!(self.status(), Status::CanRun) } - // pub fn fiber(&self) -> &Fiber { - // // TODO: Remove before merging the PR - // todo!() - // } - // pub fn cloned_tracer(&self) -> Tracer { - // // TODO: Remove - // self.fiber().tracer.clone() - // } - /// Can be called at any time from outside the VM to create a channel that /// can be used to communicate with the outside world. pub fn create_channel(&mut self) -> ChannelId { @@ -276,7 +272,7 @@ impl Vm { ); // Choose a random fiber to run. - let mut fiber_id = self.root_fiber.unwrap(); + let mut fiber_id = FiberId::root(); let fiber = loop { match self.fibers.get_mut(&fiber_id).unwrap() { FiberTree::Single(Single { fiber, .. }) => break fiber, @@ -292,8 +288,13 @@ impl Vm { return; } - let mut tracer = tracer.in_fiber_tracer(fiber_id); - fiber.run(use_provider, execution_controller, &mut *tracer); + tracer.fiber_execution_started(fiber_id); + fiber.run( + use_provider, + execution_controller, + &mut *tracer.in_fiber_tracer(fiber_id), + ); + tracer.fiber_execution_ended(fiber_id); let is_finished = match fiber.status() { fiber::Status::Running => false, @@ -308,10 +309,11 @@ impl Vm { }), ); fiber.complete_channel_create(channel_id); + tracer.channel_created(channel_id); false } fiber::Status::Sending { channel, packet } => { - self.send_to_channel(Some(fiber_id), channel, packet); + self.send_to_channel(tracer, Some(fiber_id), channel, packet); false } fiber::Status::Receiving { channel } => { @@ -378,15 +380,17 @@ impl Vm { } fiber::Status::Done => { info!("A fiber is done."); + tracer.fiber_done(fiber_id); true } fiber::Status::Panicked { reason } => { warn!("A fiber panicked because {reason}."); + tracer.fiber_panicked(fiber_id, None); true } }; - if is_finished && fiber_id != self.root_fiber.unwrap() { + if is_finished && fiber_id != FiberId::root() { let single = self .fibers .remove(&fiber_id) @@ -411,15 +415,17 @@ impl Vm { parallel.return_value = Some(return_value) } ChildKind::SpawnedChild(return_channel) => { - self.send_to_channel(None, return_channel, return_value) + self.send_to_channel(tracer, None, return_channel, return_value) } } if is_finished { - self.finish_parallel(parent, Ok(())) + self.finish_parallel(tracer, parent, Some(fiber_id), Ok(())) } } - Err(panic_reason) => self.finish_parallel(parent, Err(panic_reason)), + Err(panic_reason) => { + self.finish_parallel(tracer, parent, Some(fiber_id), Err(panic_reason)) + } } } FiberTree::Try(Try { .. }) => { @@ -461,7 +467,13 @@ impl Vm { } } } - fn finish_parallel(&mut self, parallel_id: FiberId, result: Result<(), String>) { + fn finish_parallel( + &mut self, + tracer: &mut dyn Tracer, + parallel_id: FiberId, + causing_child: Option, + result: Result<(), String>, + ) { let parallel = self .fibers .get_mut(¶llel_id) @@ -470,7 +482,7 @@ impl Vm { .unwrap(); for child_id in parallel.children.clone().into_keys() { - self.cancel(child_id); + self.cancel(tracer, child_id); } self.fibers.replace(parallel_id, |tree| { @@ -483,8 +495,9 @@ impl Vm { paused_fiber.fiber.complete_parallel_scope(result); FiberTree::Single(paused_fiber) }); + tracer.fiber_panicked(parallel_id, causing_child); } - fn cancel(&mut self, fiber: FiberId) { + fn cancel(&mut self, tracer: &mut dyn Tracer, fiber: FiberId) { match self.fibers.remove(&fiber).unwrap() { FiberTree::Single(_) => {} FiberTree::Parallel(Parallel { @@ -496,15 +509,17 @@ impl Vm { .to_nursery() .unwrap(); for child_fiber in children.keys() { - self.cancel(*child_fiber); + self.cancel(tracer, *child_fiber); } } - FiberTree::Try(Try { child, .. }) => self.cancel(child), + FiberTree::Try(Try { child, .. }) => self.cancel(tracer, child), } + tracer.fiber_canceled(fiber); } fn send_to_channel( &mut self, + tracer: &mut dyn Tracer, performing_fiber: Option, channel_id: ChannelId, packet: Packet, @@ -556,9 +571,13 @@ impl Vm { .unwrap() .children .insert(child_id, ChildKind::SpawnedChild(return_channel)); + + tracer.fiber_created(child_id); } None => self.finish_parallel( + tracer, parent_id, + performing_fiber, Err("a nursery received an invalid message".to_string()), ), } diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index e8489a617..120ecde7f 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -6,11 +6,17 @@ use super::{ FiberId, Heap, }; use crate::{compiler::hir::Id, module::Module}; -use std::{collections::HashMap, time::Instant}; +use itertools::Itertools; +use std::{collections::HashMap, fmt, time::Instant}; pub trait Tracer { + fn fiber_created(&mut self, fiber: FiberId); + fn fiber_done(&mut self, fiber: FiberId); + fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option); + fn fiber_canceled(&mut self, fiber: FiberId); fn fiber_execution_started(&mut self, fiber: FiberId); fn fiber_execution_ended(&mut self, fiber: FiberId); + fn channel_created(&mut self, channel: ChannelId); fn sent_to_channel(&mut self, value: Pointer, from: FiberId, to: ChannelId); fn received_from_channel(&mut self, value: Pointer, from: ChannelId, to: FiberId); @@ -36,8 +42,13 @@ pub trait InFiberTracer<'a> { pub struct DummyTracer; pub struct DummyInFiberTracer; impl Tracer for DummyTracer { + fn fiber_created(&mut self, _fiber: FiberId) {} + fn fiber_done(&mut self, _fiber: FiberId) {} + fn fiber_panicked(&mut self, _fiber: FiberId, _panicked_child: Option) {} + fn fiber_canceled(&mut self, _fiber: FiberId) {} fn fiber_execution_started(&mut self, _fiber: FiberId) {} fn fiber_execution_ended(&mut self, _fiber: FiberId) {} + fn channel_created(&mut self, _channel: ChannelId) {} fn sent_to_channel(&mut self, _value: Pointer, _from: FiberId, _to: ChannelId) {} fn received_from_channel(&mut self, _value: Pointer, _from: ChannelId, _to: FiberId) {} @@ -82,6 +93,7 @@ pub enum Event { }, FiberPanicked { fiber: FiberId, + panicked_child: Option, }, FiberCanceled { fiber: FiberId, @@ -160,17 +172,35 @@ impl FullTracer { let address_map = self .transferred_objects .entry(fiber) - .or_insert_with(|| HashMap::new()); + .or_insert_with(HashMap::new); heap.clone_single_to_other_heap_with_existing_mapping(&mut self.heap, value, address_map) } } impl Tracer for FullTracer { + fn fiber_created(&mut self, fiber: FiberId) { + self.push(Event::FiberCreated { fiber }); + } + fn fiber_done(&mut self, fiber: FiberId) { + self.push(Event::FiberDone { fiber }); + } + fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option) { + self.push(Event::FiberPanicked { + fiber, + panicked_child, + }); + } + fn fiber_canceled(&mut self, fiber: FiberId) { + self.push(Event::FiberCanceled { fiber }); + } fn fiber_execution_started(&mut self, fiber: FiberId) { self.push(Event::FiberExecutionStarted { fiber }); } fn fiber_execution_ended(&mut self, fiber: FiberId) { self.push(Event::FiberExecutionEnded { fiber }); } + fn channel_created(&mut self, channel: ChannelId) { + self.push(Event::ChannelCreated { channel }); + } fn sent_to_channel(&mut self, value: Pointer, from: FiberId, to: ChannelId) { self.push(Event::SentToChannel { value, from, to }); } @@ -245,3 +275,73 @@ impl<'a> InFiberTracer<'a> for FullInFiberTracer<'a> { self.push(InFiberEvent::NeedsEnded); } } + +impl fmt::Debug for FullTracer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let start = self.events.first().map(|event| event.when); + for event in &self.events { + writeln!( + f, + "{:?} us: {}", + event.when.duration_since(start.unwrap()).as_micros(), + match &event.event { + Event::FiberCreated { fiber } => format!("{fiber:?}: created"), + Event::FiberDone { fiber } => format!("{fiber:?}: done"), + Event::FiberPanicked { + fiber, + panicked_child, + } => format!( + "{fiber:?}: panicked{}", + if let Some(child) = panicked_child { + format!(" because child {child:?} panicked") + } else { + "".to_string() + } + ), + Event::FiberCanceled { fiber } => format!("{fiber:?}: canceled"), + Event::FiberExecutionStarted { fiber } => + format!("{fiber:?}: execution started"), + Event::FiberExecutionEnded { fiber } => format!("{fiber:?}: execution ended"), + Event::ChannelCreated { channel } => format!("{channel:?}: created"), + Event::SentToChannel { value, from, to } => + format!("{from:?} sent {} to {to:?}", value.format(&self.heap)), + Event::ReceivedFromChannel { value, from, to } => + format!("{to:?} received {} from {from:?}", value.format(&self.heap)), + Event::InFiber { fiber, event } => format!( + "{fiber:?}: {}", + match event { + InFiberEvent::ModuleStarted { module } => + format!("module {module} started"), + InFiberEvent::ModuleEnded { export_map } => format!( + "module ended and exported {}", + export_map.format(&self.heap) + ), + InFiberEvent::ValueEvaluated { id, value } => + format!("value {id} is {}", value.format(&self.heap)), + InFiberEvent::FoundFuzzableClosure { id, .. } => + format!("found fuzzable closure {id}"), + InFiberEvent::CallStarted { id, closure, args } => format!( + "call {id} started: {} {}", + closure.format(&self.heap), + args.iter().map(|arg| arg.format(&self.heap)).join(" ") + ), + InFiberEvent::CallEnded { return_value } => + format!("call ended: {}", return_value.format(&self.heap)), + InFiberEvent::NeedsStarted { + id, + condition, + reason, + } => format!( + "needs {id} started: needs {} {}", + condition.format(&self.heap), + reason.format(&self.heap) + ), + InFiberEvent::NeedsEnded => "needs ended".to_string(), + } + ), + } + )?; + } + Ok(()) + } +} diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs index 6563a0ef6..75878c98a 100644 --- a/compiler/src/vm/tracer/stack_trace.rs +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -77,72 +77,94 @@ impl FullTracer { } stacks } - pub fn format_stack_traces(&self, db: &Database) -> String { + pub fn format_stack_trace(&self, db: &Database, stack: &[StackEntry]) -> String { let mut lines = vec![]; - for (fiber, stack) in self.stack_traces() { - lines.push(format!("{fiber:?}:")); - for entry in stack.iter().rev() { - let hir_id = match entry { - StackEntry::Call { id, .. } => Some(id), - StackEntry::Needs { id, .. } => Some(id), - StackEntry::Module { .. } => None, - }; - let (cst_id, span) = if let Some(hir_id) = hir_id { - let module = hir_id.module.clone(); - let cst_id = db.hir_to_cst_id(hir_id.clone()); - let cst = cst_id.map(|id| db.find_cst(module.clone(), id)); - let span = cst.map(|cst| { - ( - db.offset_to_lsp(module.clone(), cst.span.start), - db.offset_to_lsp(module.clone(), cst.span.end), - ) - }); - (cst_id, span) - } else { - (None, None) - }; - let caller_location_string = format!( + for entry in stack.iter().rev() { + let hir_id = match entry { + StackEntry::Call { id, .. } => Some(id), + StackEntry::Needs { id, .. } => Some(id), + StackEntry::Module { .. } => None, + }; + let (cst_id, span) = if let Some(hir_id) = hir_id { + let module = hir_id.module.clone(); + let cst_id = db.hir_to_cst_id(hir_id.clone()); + let cst = cst_id.map(|id| db.find_cst(module.clone(), id)); + let span = cst.map(|cst| { + ( + db.offset_to_lsp(module.clone(), cst.span.start), + db.offset_to_lsp(module.clone(), cst.span.end), + ) + }); + (cst_id, span) + } else { + (None, None) + }; + let caller_location_string = format!( + "{} {}", + hir_id + .map(|id| format!("{id}")) + .unwrap_or_else(|| "".to_string()), + span.map(|((start_line, start_col), (end_line, end_col))| format!( + "{}:{} – {}:{}", + start_line, start_col, end_line, end_col + )) + .unwrap_or_else(|| "".to_string()) + ); + let call_string = match entry { + StackEntry::Call { closure, args, .. } => format!( "{} {}", - hir_id - .map(|id| format!("{id}")) - .unwrap_or_else(|| "".to_string()), - span.map(|((start_line, start_col), (end_line, end_col))| format!( - "{}:{} – {}:{}", - start_line, start_col, end_line, end_col - )) - .unwrap_or_else(|| "".to_string()) - ); - let call_string = match entry { - StackEntry::Call { closure, args, .. } => format!( - "{} {}", - cst_id - .and_then(|id| { - let cst = db.find_cst(hir_id.unwrap().module.clone(), id); - match cst.kind { - CstKind::Call { receiver, .. } => { - receiver.extract_receiver_name() - } - _ => None, - } - }) - .unwrap_or_else(|| closure.format(&self.heap)), - args.iter().map(|arg| arg.format(&self.heap)).join(" ") - ), - StackEntry::Needs { - condition, reason, .. - } => format!( - "needs {} {}", - condition.format(&self.heap), - reason.format(&self.heap), - ), - StackEntry::Module { module } => format!("module {module}"), - }; - lines.push(format!("{caller_location_string:90} {call_string}")); - } + cst_id + .and_then(|id| { + let cst = db.find_cst(hir_id.unwrap().module.clone(), id); + match cst.kind { + CstKind::Call { receiver, .. } => receiver.extract_receiver_name(), + _ => None, + } + }) + .unwrap_or_else(|| closure.format(&self.heap)), + args.iter().map(|arg| arg.format(&self.heap)).join(" ") + ), + StackEntry::Needs { + condition, reason, .. + } => format!( + "needs {} {}", + condition.format(&self.heap), + reason.format(&self.heap), + ), + StackEntry::Module { module } => format!("module {module}"), + }; + lines.push(format!("{caller_location_string:90} {call_string}")); } lines.join("\n") } + /// When a VM panics, some child fiber might be responsible for that. This + /// function returns a formatted stack trace spanning all fibers in the + /// chain from the panicking root fiber until the concrete failing needs. + pub fn format_panic_stack_trace_to_root_fiber(&self, db: &Database) -> String { + let mut panicking_fiber_chain = vec![FiberId::root()]; + for timed_event in self.events.iter().rev() { + if let Event::FiberPanicked { + fiber, + panicked_child, + } = timed_event.event + { + if fiber == *panicking_fiber_chain.last().unwrap() { + match panicked_child { + Some(child) => panicking_fiber_chain.push(child), + None => break, + } + } + } + } + + let stack_traces = self.stack_traces(); + panicking_fiber_chain + .into_iter() + .rev() + .map(|fiber| self.format_stack_trace(db, &stack_traces[&fiber])) + .join("\n(fiber boundary)\n") + } } impl Cst { From add41fcdf28b6b5975de69950f402f6520e1b1f8 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Wed, 5 Oct 2022 17:57:52 +0200 Subject: [PATCH 07/44] Move tracer into its own component --- compiler/src/fuzzer/fuzzer.rs | 2 +- compiler/src/fuzzer/mod.rs | 2 +- compiler/src/fuzzer/utils.rs | 2 +- compiler/src/language_server/hints/constant_evaluator.rs | 2 +- compiler/src/main.rs | 3 ++- compiler/src/{vm => }/tracer/full_trace.rs | 0 compiler/src/{vm => }/tracer/mod.rs | 8 ++++---- compiler/src/{vm => }/tracer/stack_trace.rs | 3 ++- compiler/src/vm/builtin_functions.rs | 5 +++-- compiler/src/vm/fiber.rs | 4 ++-- compiler/src/vm/mod.rs | 7 +++---- compiler/src/vm/use_module.rs | 2 +- 12 files changed, 21 insertions(+), 19 deletions(-) rename compiler/src/{vm => }/tracer/full_trace.rs (100%) rename compiler/src/{vm => }/tracer/mod.rs (99%) rename compiler/src/{vm => }/tracer/stack_trace.rs (98%) diff --git a/compiler/src/fuzzer/fuzzer.rs b/compiler/src/fuzzer/fuzzer.rs index 16d569eb2..6268fc5bb 100644 --- a/compiler/src/fuzzer/fuzzer.rs +++ b/compiler/src/fuzzer/fuzzer.rs @@ -2,10 +2,10 @@ use super::{generator::generate_n_values, utils::did_need_in_closure_cause_panic use crate::{ compiler::hir, database::Database, + tracer::{DummyTracer, FullTracer}, vm::{ self, context::{ExecutionController, UseProvider}, - tracer::{DummyTracer, FullTracer}, Closure, Heap, Packet, Pointer, Vm, }, }; diff --git a/compiler/src/fuzzer/mod.rs b/compiler/src/fuzzer/mod.rs index a4606a14f..203d1af1e 100644 --- a/compiler/src/fuzzer/mod.rs +++ b/compiler/src/fuzzer/mod.rs @@ -7,9 +7,9 @@ use crate::{ compiler::hir::Id, database::Database, module::Module, + tracer::DummyTracer, vm::{ context::{DbUseProvider, RunForever, RunLimitedNumberOfInstructions}, - tracer::DummyTracer, Closure, Heap, Pointer, Vm, }, }; diff --git a/compiler/src/fuzzer/utils.rs b/compiler/src/fuzzer/utils.rs index 7d94e6337..76419ebfa 100644 --- a/compiler/src/fuzzer/utils.rs +++ b/compiler/src/fuzzer/utils.rs @@ -1,7 +1,7 @@ use crate::{ compiler::hir::{self, Expression, HirDb, Lambda}, database::Database, - vm::tracer::{FullTracer, Tracer}, + tracer::{FullTracer, Tracer}, }; pub fn did_need_in_closure_cause_panic(db: &Database, closure_id: &hir::Id) -> bool { diff --git a/compiler/src/language_server/hints/constant_evaluator.rs b/compiler/src/language_server/hints/constant_evaluator.rs index 5de1ae782..360cf1e9d 100644 --- a/compiler/src/language_server/hints/constant_evaluator.rs +++ b/compiler/src/language_server/hints/constant_evaluator.rs @@ -9,10 +9,10 @@ use crate::{ database::Database, language_server::hints::{utils::id_to_end_of_line, HintKind}, module::Module, + tracer::{stack_trace::StackEntry, DummyTracer, FullTracer}, vm::{ self, context::{DbUseProvider, RunLimitedNumberOfInstructions}, - tracer::{stack_trace::StackEntry, DummyTracer, FullTracer}, Closure, Heap, Pointer, Vm, }, }; diff --git a/compiler/src/main.rs b/compiler/src/main.rs index 1fded3130..ea7cade00 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -12,6 +12,7 @@ mod database; mod fuzzer; mod language_server; mod module; +mod tracer; mod vm; use crate::{ @@ -27,9 +28,9 @@ use crate::{ database::Database, language_server::utils::LspPositionConversion, module::{Module, ModuleKind}, + tracer::{DummyTracer, FullTracer}, vm::{ context::{DbUseProvider, RunForever, RunLimitedNumberOfInstructions}, - tracer::{DummyTracer, FullTracer}, Closure, Status, Struct, Vm, }, }; diff --git a/compiler/src/vm/tracer/full_trace.rs b/compiler/src/tracer/full_trace.rs similarity index 100% rename from compiler/src/vm/tracer/full_trace.rs rename to compiler/src/tracer/full_trace.rs diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/tracer/mod.rs similarity index 99% rename from compiler/src/vm/tracer/mod.rs rename to compiler/src/tracer/mod.rs index 120ecde7f..c329b4c93 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/tracer/mod.rs @@ -1,11 +1,11 @@ // mod full_trace; pub mod stack_trace; -use super::{ - heap::{ChannelId, Pointer}, - FiberId, Heap, +use crate::{ + compiler::hir::Id, + module::Module, + vm::{ChannelId, FiberId, Heap, Pointer}, }; -use crate::{compiler::hir::Id, module::Module}; use itertools::Itertools; use std::{collections::HashMap, fmt, time::Instant}; diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/tracer/stack_trace.rs similarity index 98% rename from compiler/src/vm/tracer/stack_trace.rs rename to compiler/src/tracer/stack_trace.rs index 75878c98a..956c4c610 100644 --- a/compiler/src/vm/tracer/stack_trace.rs +++ b/compiler/src/tracer/stack_trace.rs @@ -1,5 +1,6 @@ -use super::{super::heap::Pointer, Event, FiberId, FullTracer, InFiberEvent}; +use super::{Event, FullTracer, InFiberEvent}; use crate::{ + vm::{Pointer, FiberId}, compiler::{ ast_to_hir::AstToHir, cst::{Cst, CstDb, CstKind}, diff --git a/compiler/src/vm/builtin_functions.rs b/compiler/src/vm/builtin_functions.rs index 4272bc3e3..f2c26646d 100644 --- a/compiler/src/vm/builtin_functions.rs +++ b/compiler/src/vm/builtin_functions.rs @@ -3,10 +3,11 @@ use super::{ context::PanickingUseProvider, fiber::{Fiber, Status}, heap::{ChannelId, Closure, Data, Int, Pointer, ReceivePort, SendPort, Struct, Symbol, Text}, - tracer::DummyInFiberTracer, Heap, }; -use crate::{builtin_functions::BuiltinFunction, compiler::lir::Instruction}; +use crate::{ + builtin_functions::BuiltinFunction, compiler::lir::Instruction, tracer::DummyInFiberTracer, +}; use itertools::Itertools; use num_bigint::BigInt; use num_integer::Integer; diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index 2d1557618..51eb68553 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -2,12 +2,12 @@ use super::{ channel::{Capacity, Packet}, context::{ExecutionController, UseProvider}, heap::{Builtin, ChannelId, Closure, Data, Heap, Pointer}, - tracer::InFiberTracer, }; use crate::{ compiler::lir::Instruction, module::Module, - vm::{context::PanickingUseProvider, tracer::DummyInFiberTracer}, + tracer::{DummyInFiberTracer, InFiberTracer}, + vm::context::PanickingUseProvider, }; use itertools::Itertools; use std::collections::HashMap; diff --git a/compiler/src/vm/mod.rs b/compiler/src/vm/mod.rs index 51b914b03..d77232b34 100644 --- a/compiler/src/vm/mod.rs +++ b/compiler/src/vm/mod.rs @@ -3,7 +3,6 @@ mod channel; pub mod context; mod fiber; mod heap; -pub mod tracer; mod use_module; use self::{ @@ -12,14 +11,14 @@ use self::{ CombiningExecutionController, ExecutionController, RunLimitedNumberOfInstructions, UseProvider, }, - heap::{ChannelId, SendPort}, - tracer::Tracer, + heap::SendPort, }; pub use self::{ channel::Packet, fiber::Fiber, - heap::{Closure, Heap, Object, Pointer, Struct}, + heap::{ChannelId, Closure, Heap, Object, Pointer, Struct}, }; +use crate::tracer::Tracer; use itertools::Itertools; use rand::seq::SliceRandom; use std::{ diff --git a/compiler/src/vm/use_module.rs b/compiler/src/vm/use_module.rs index 5dc670ef5..2b929ffb6 100644 --- a/compiler/src/vm/use_module.rs +++ b/compiler/src/vm/use_module.rs @@ -1,12 +1,12 @@ use super::{ context::{PanickingUseProvider, UseProvider, UseResult}, heap::{Closure, Heap, Pointer, Text}, - tracer::DummyInFiberTracer, Fiber, }; use crate::{ compiler::lir::Instruction, module::{Module, ModuleKind}, + tracer::DummyInFiberTracer, }; use itertools::Itertools; From 316fe76b3da31678c206eae9e7e91af60e1a3bc3 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Wed, 5 Oct 2022 18:30:37 +0200 Subject: [PATCH 08/44] Revert " Move tracer into its own component" This reverts commit add41fcdf28b6b5975de69950f402f6520e1b1f8. --- compiler/src/fuzzer/fuzzer.rs | 2 +- compiler/src/fuzzer/mod.rs | 2 +- compiler/src/fuzzer/utils.rs | 2 +- compiler/src/language_server/hints/constant_evaluator.rs | 2 +- compiler/src/main.rs | 3 +-- compiler/src/vm/builtin_functions.rs | 5 ++--- compiler/src/vm/fiber.rs | 4 ++-- compiler/src/vm/mod.rs | 7 ++++--- compiler/src/{ => vm}/tracer/full_trace.rs | 0 compiler/src/{ => vm}/tracer/mod.rs | 8 ++++---- compiler/src/{ => vm}/tracer/stack_trace.rs | 3 +-- compiler/src/vm/use_module.rs | 2 +- 12 files changed, 19 insertions(+), 21 deletions(-) rename compiler/src/{ => vm}/tracer/full_trace.rs (100%) rename compiler/src/{ => vm}/tracer/mod.rs (99%) rename compiler/src/{ => vm}/tracer/stack_trace.rs (98%) diff --git a/compiler/src/fuzzer/fuzzer.rs b/compiler/src/fuzzer/fuzzer.rs index 6268fc5bb..16d569eb2 100644 --- a/compiler/src/fuzzer/fuzzer.rs +++ b/compiler/src/fuzzer/fuzzer.rs @@ -2,10 +2,10 @@ use super::{generator::generate_n_values, utils::did_need_in_closure_cause_panic use crate::{ compiler::hir, database::Database, - tracer::{DummyTracer, FullTracer}, vm::{ self, context::{ExecutionController, UseProvider}, + tracer::{DummyTracer, FullTracer}, Closure, Heap, Packet, Pointer, Vm, }, }; diff --git a/compiler/src/fuzzer/mod.rs b/compiler/src/fuzzer/mod.rs index 203d1af1e..a4606a14f 100644 --- a/compiler/src/fuzzer/mod.rs +++ b/compiler/src/fuzzer/mod.rs @@ -7,9 +7,9 @@ use crate::{ compiler::hir::Id, database::Database, module::Module, - tracer::DummyTracer, vm::{ context::{DbUseProvider, RunForever, RunLimitedNumberOfInstructions}, + tracer::DummyTracer, Closure, Heap, Pointer, Vm, }, }; diff --git a/compiler/src/fuzzer/utils.rs b/compiler/src/fuzzer/utils.rs index 76419ebfa..7d94e6337 100644 --- a/compiler/src/fuzzer/utils.rs +++ b/compiler/src/fuzzer/utils.rs @@ -1,7 +1,7 @@ use crate::{ compiler::hir::{self, Expression, HirDb, Lambda}, database::Database, - tracer::{FullTracer, Tracer}, + vm::tracer::{FullTracer, Tracer}, }; pub fn did_need_in_closure_cause_panic(db: &Database, closure_id: &hir::Id) -> bool { diff --git a/compiler/src/language_server/hints/constant_evaluator.rs b/compiler/src/language_server/hints/constant_evaluator.rs index 360cf1e9d..5de1ae782 100644 --- a/compiler/src/language_server/hints/constant_evaluator.rs +++ b/compiler/src/language_server/hints/constant_evaluator.rs @@ -9,10 +9,10 @@ use crate::{ database::Database, language_server::hints::{utils::id_to_end_of_line, HintKind}, module::Module, - tracer::{stack_trace::StackEntry, DummyTracer, FullTracer}, vm::{ self, context::{DbUseProvider, RunLimitedNumberOfInstructions}, + tracer::{stack_trace::StackEntry, DummyTracer, FullTracer}, Closure, Heap, Pointer, Vm, }, }; diff --git a/compiler/src/main.rs b/compiler/src/main.rs index ea7cade00..1fded3130 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -12,7 +12,6 @@ mod database; mod fuzzer; mod language_server; mod module; -mod tracer; mod vm; use crate::{ @@ -28,9 +27,9 @@ use crate::{ database::Database, language_server::utils::LspPositionConversion, module::{Module, ModuleKind}, - tracer::{DummyTracer, FullTracer}, vm::{ context::{DbUseProvider, RunForever, RunLimitedNumberOfInstructions}, + tracer::{DummyTracer, FullTracer}, Closure, Status, Struct, Vm, }, }; diff --git a/compiler/src/vm/builtin_functions.rs b/compiler/src/vm/builtin_functions.rs index f2c26646d..4272bc3e3 100644 --- a/compiler/src/vm/builtin_functions.rs +++ b/compiler/src/vm/builtin_functions.rs @@ -3,11 +3,10 @@ use super::{ context::PanickingUseProvider, fiber::{Fiber, Status}, heap::{ChannelId, Closure, Data, Int, Pointer, ReceivePort, SendPort, Struct, Symbol, Text}, + tracer::DummyInFiberTracer, Heap, }; -use crate::{ - builtin_functions::BuiltinFunction, compiler::lir::Instruction, tracer::DummyInFiberTracer, -}; +use crate::{builtin_functions::BuiltinFunction, compiler::lir::Instruction}; use itertools::Itertools; use num_bigint::BigInt; use num_integer::Integer; diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index 51eb68553..2d1557618 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -2,12 +2,12 @@ use super::{ channel::{Capacity, Packet}, context::{ExecutionController, UseProvider}, heap::{Builtin, ChannelId, Closure, Data, Heap, Pointer}, + tracer::InFiberTracer, }; use crate::{ compiler::lir::Instruction, module::Module, - tracer::{DummyInFiberTracer, InFiberTracer}, - vm::context::PanickingUseProvider, + vm::{context::PanickingUseProvider, tracer::DummyInFiberTracer}, }; use itertools::Itertools; use std::collections::HashMap; diff --git a/compiler/src/vm/mod.rs b/compiler/src/vm/mod.rs index d77232b34..51b914b03 100644 --- a/compiler/src/vm/mod.rs +++ b/compiler/src/vm/mod.rs @@ -3,6 +3,7 @@ mod channel; pub mod context; mod fiber; mod heap; +pub mod tracer; mod use_module; use self::{ @@ -11,14 +12,14 @@ use self::{ CombiningExecutionController, ExecutionController, RunLimitedNumberOfInstructions, UseProvider, }, - heap::SendPort, + heap::{ChannelId, SendPort}, + tracer::Tracer, }; pub use self::{ channel::Packet, fiber::Fiber, - heap::{ChannelId, Closure, Heap, Object, Pointer, Struct}, + heap::{Closure, Heap, Object, Pointer, Struct}, }; -use crate::tracer::Tracer; use itertools::Itertools; use rand::seq::SliceRandom; use std::{ diff --git a/compiler/src/tracer/full_trace.rs b/compiler/src/vm/tracer/full_trace.rs similarity index 100% rename from compiler/src/tracer/full_trace.rs rename to compiler/src/vm/tracer/full_trace.rs diff --git a/compiler/src/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs similarity index 99% rename from compiler/src/tracer/mod.rs rename to compiler/src/vm/tracer/mod.rs index c329b4c93..120ecde7f 100644 --- a/compiler/src/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -1,11 +1,11 @@ // mod full_trace; pub mod stack_trace; -use crate::{ - compiler::hir::Id, - module::Module, - vm::{ChannelId, FiberId, Heap, Pointer}, +use super::{ + heap::{ChannelId, Pointer}, + FiberId, Heap, }; +use crate::{compiler::hir::Id, module::Module}; use itertools::Itertools; use std::{collections::HashMap, fmt, time::Instant}; diff --git a/compiler/src/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs similarity index 98% rename from compiler/src/tracer/stack_trace.rs rename to compiler/src/vm/tracer/stack_trace.rs index 956c4c610..75878c98a 100644 --- a/compiler/src/tracer/stack_trace.rs +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -1,6 +1,5 @@ -use super::{Event, FullTracer, InFiberEvent}; +use super::{super::heap::Pointer, Event, FiberId, FullTracer, InFiberEvent}; use crate::{ - vm::{Pointer, FiberId}, compiler::{ ast_to_hir::AstToHir, cst::{Cst, CstDb, CstKind}, diff --git a/compiler/src/vm/use_module.rs b/compiler/src/vm/use_module.rs index 2b929ffb6..5dc670ef5 100644 --- a/compiler/src/vm/use_module.rs +++ b/compiler/src/vm/use_module.rs @@ -1,12 +1,12 @@ use super::{ context::{PanickingUseProvider, UseProvider, UseResult}, heap::{Closure, Heap, Pointer, Text}, + tracer::DummyInFiberTracer, Fiber, }; use crate::{ compiler::lir::Instruction, module::{Module, ModuleKind}, - tracer::DummyInFiberTracer, }; use itertools::Itertools; From 61ab4128cb775faee95d3e633422db98b6ba8061 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Fri, 7 Oct 2022 17:21:03 +0200 Subject: [PATCH 09/44] Add responsibility to VM --- compiler/src/compiler/hir_to_lir.rs | 11 +++++++++++ compiler/src/compiler/lir.rs | 23 +++++++++++++++++++--- compiler/src/vm/fiber.rs | 30 ++++++++++++++++++++++++++++- compiler/src/vm/heap/mod.rs | 1 + compiler/src/vm/heap/object.rs | 8 +++++++- 5 files changed, 68 insertions(+), 5 deletions(-) diff --git a/compiler/src/compiler/hir_to_lir.rs b/compiler/src/compiler/hir_to_lir.rs index ca894beb5..22e84e9bb 100644 --- a/compiler/src/compiler/hir_to_lir.rs +++ b/compiler/src/compiler/hir_to_lir.rs @@ -82,6 +82,7 @@ impl LoweringContext { .collect_vec(), lambda.parameters.len(), instructions, + !lambda.fuzzable, ); if lambda.fuzzable { self.emit_register_fuzzable_closure(id.clone()); @@ -96,9 +97,11 @@ impl LoweringContext { } self.emit_push_from_stack(function.clone()); + self.emit_start_responsibility(id.clone()); self.emit_trace_call_starts(id.clone(), arguments.len()); self.emit_call(id.clone(), arguments.len()); self.emit_trace_call_ends(); + self.emit_end_responsibility(); } Expression::Builtin(builtin) => { self.emit_create_builtin(id.clone(), *builtin); @@ -147,11 +150,13 @@ impl LoweringContext { captured: Vec, num_args: usize, instructions: Vec, + is_curly: bool, ) { self.emit(Instruction::CreateClosure { captured, num_args, body: instructions, + is_curly, }); self.stack.push(id); } @@ -184,6 +189,12 @@ impl LoweringContext { self.emit(Instruction::UseModule { current_module }); self.stack.push(id); // exported definitions } + fn emit_start_responsibility(&mut self, responsible: hir::Id) { + self.emit(Instruction::StartResponsibility(responsible)); + } + fn emit_end_responsibility(&mut self) { + self.emit(Instruction::EndResponsibility); + } fn emit_needs(&mut self, id: hir::Id) { self.stack.pop(); // reason self.stack.pop(); // condition diff --git a/compiler/src/compiler/lir.rs b/compiler/src/compiler/lir.rs index d1058ad6b..10c55773a 100644 --- a/compiler/src/compiler/lir.rs +++ b/compiler/src/compiler/lir.rs @@ -1,4 +1,4 @@ -use super::error::CompilerError; +use super::{error::CompilerError, hir::Id}; use crate::{builtin_functions::BuiltinFunction, hir, module::Module}; use itertools::Itertools; use num_bigint::BigUint; @@ -36,6 +36,7 @@ pub enum Instruction { captured: Vec, num_args: usize, body: Vec, + is_curly: bool, }, /// Pushes a builtin function. @@ -89,6 +90,12 @@ pub enum Instruction { current_module: Module, }, + /// Contrary to other languages, in Candy it's always clear who's fault it + /// is when a program panics. Each fiber maintains a responsibility stack + /// which notes which call-site is responsible for needs to be fulfilled. + StartResponsibility(Id), + EndResponsibility, + /// Pops a boolean condition and a reason. If the condition is true, it /// just pushes Nothing. If the condition is false, it panics with the /// reason. @@ -133,10 +140,11 @@ impl Display for Instruction { captured, num_args, body: instructions, + is_curly, } => { write!( f, - "createClosure with {num_args} {} capturing {}", + "createClosure with {num_args} {} capturing {} {}", if *num_args == 1 { "argument" } else { @@ -146,7 +154,12 @@ impl Display for Instruction { "nothing".to_string() } else { captured.iter().join(", ") - } + }, + if *is_curly { + "(is curly)" + } else { + "(is not curly)" + }, )?; for instruction in instructions { let indented = format!("{instruction}") @@ -171,6 +184,10 @@ impl Display for Instruction { Instruction::UseModule { current_module } => { write!(f, "useModule (currently in {})", current_module) } + Instruction::StartResponsibility(responsible) => { + write!(f, "responsibility of {responsible} starts") + } + Instruction::EndResponsibility => write!(f, "responsibility ends"), Instruction::Needs => write!(f, "needs"), Instruction::RegisterFuzzableClosure(hir_id) => { write!(f, "registerFuzzableClosure {hir_id}") diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index 2d1557618..52611bb71 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -5,7 +5,7 @@ use super::{ tracer::InFiberTracer, }; use crate::{ - compiler::lir::Instruction, + compiler::{hir::Id, lir::Instruction}, module::Module, vm::{context::PanickingUseProvider, tracer::DummyInFiberTracer}, }; @@ -24,6 +24,7 @@ pub struct Fiber { pub data_stack: Vec, pub call_stack: Vec, pub import_stack: Vec, + pub responsible_stack: Vec, pub heap: Heap, } @@ -70,6 +71,7 @@ impl Fiber { data_stack: vec![], call_stack: vec![], import_stack: vec![], + responsible_stack: vec![], heap, } } @@ -268,6 +270,7 @@ impl Fiber { num_args, body, captured, + is_curly, } => { let captured = captured .iter() @@ -280,6 +283,11 @@ impl Fiber { captured, num_args, body, + responsible: if is_curly { + None + } else { + self.responsible_stack.last().cloned() + }, }); self.data_stack.push(address); } @@ -313,6 +321,7 @@ impl Fiber { Data::Closure(Closure { captured, num_args: expected_num_args, + responsible, .. }) => { if num_args != expected_num_args { @@ -326,6 +335,9 @@ impl Fiber { self.heap.dup(captured); } self.data_stack.append(&mut args); + if let Some(responsible) = responsible { + self.responsible_stack.push(responsible); + } self.next_instruction = InstructionPointer::start_of_closure(closure_address); } @@ -342,6 +354,16 @@ impl Fiber { }; } Instruction::Return => { + let closure: Closure = self + .heap + .get(self.next_instruction.closure) + .data + .clone() + .try_into() + .unwrap(); + if closure.responsible.is_some() { + self.responsible_stack.pop().unwrap(); + } self.heap.drop(self.next_instruction.closure); let caller = self.call_stack.pop().unwrap(); self.next_instruction = caller; @@ -355,6 +377,12 @@ impl Fiber { } } } + Instruction::StartResponsibility(responsible) => { + self.responsible_stack.push(responsible); + } + Instruction::EndResponsibility => { + self.responsible_stack.pop().unwrap(); + } Instruction::Needs => { let reason = self.data_stack.pop().unwrap(); let condition = self.data_stack.pop().unwrap(); diff --git a/compiler/src/vm/heap/mod.rs b/compiler/src/vm/heap/mod.rs index 368866f28..59f60f053 100644 --- a/compiler/src/vm/heap/mod.rs +++ b/compiler/src/vm/heap/mod.rs @@ -199,6 +199,7 @@ impl Heap { .collect(), num_args: closure.num_args, body: closure.body.clone(), + responsible: closure.responsible.clone(), }), Data::Builtin(builtin) => Data::Builtin(builtin.clone()), Data::SendPort(port) => Data::SendPort(SendPort::new(port.channel)), diff --git a/compiler/src/vm/heap/object.rs b/compiler/src/vm/heap/object.rs index bae25b248..f713bed80 100644 --- a/compiler/src/vm/heap/object.rs +++ b/compiler/src/vm/heap/object.rs @@ -2,6 +2,7 @@ use super::{pointer::Pointer, Heap}; use crate::{ builtin_functions::BuiltinFunction, compiler::{ + hir::Id, hir_to_lir::HirToLir, lir::{Instruction, Lir}, }, @@ -60,6 +61,7 @@ pub struct Closure { pub captured: Vec, pub num_args: usize, pub body: Vec, + pub responsible: Option, } #[derive(Clone)] @@ -136,16 +138,20 @@ impl Closure { captured: vec![], num_args: 0, body: vec![ - Instruction::TraceModuleStarts { module }, + Instruction::TraceModuleStarts { + module: module.clone(), + }, Instruction::CreateClosure { captured: vec![], num_args: 0, body: lir.instructions, + is_curly: true, }, Instruction::Call { num_args: 0 }, Instruction::TraceModuleEnds, Instruction::Return, ], + responsible: None, } } pub fn of_module(db: &Database, module: Module) -> Option { From a2553d8d2955dc1e9dfb09df6526485b7e38647e Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Fri, 7 Oct 2022 22:50:25 +0200 Subject: [PATCH 10/44] Fix fault attribution --- compiler/src/fuzzer/fuzzer.rs | 5 +- .../hints/constant_evaluator.rs | 6 +- compiler/src/main.rs | 85 ++++---- compiler/src/vm/builtin_functions.rs | 2 +- compiler/src/vm/fiber.rs | 72 +++++-- compiler/src/vm/mod.rs | 36 ++-- compiler/src/vm/tracer/full_trace.rs | 201 ------------------ compiler/src/vm/tracer/mod.rs | 1 - 8 files changed, 134 insertions(+), 274 deletions(-) delete mode 100644 compiler/src/vm/tracer/full_trace.rs diff --git a/compiler/src/fuzzer/fuzzer.rs b/compiler/src/fuzzer/fuzzer.rs index 16d569eb2..ad5b75a0e 100644 --- a/compiler/src/fuzzer/fuzzer.rs +++ b/compiler/src/fuzzer/fuzzer.rs @@ -111,13 +111,12 @@ impl Fuzzer { vm::Status::WaitingForOperations => panic!("Fuzzing should not have to wait on channel operations because arguments were not channels."), // The VM finished running without panicking. vm::Status::Done => Status::new_fuzzing_attempt(&self.closure_heap, self.closure), - vm::Status::Panicked { reason } => { + vm::Status::Panicked { reason, responsible } => { // If a `needs` directly inside the tested closure was not // satisfied, then the panic is not closure's fault, but our // fault. let result = vm.tear_down(); - let is_our_fault = - did_need_in_closure_cause_panic(db, &self.closure_id); + let is_our_fault = responsible.is_none(); if is_our_fault { Status::new_fuzzing_attempt(&self.closure_heap, self.closure) } else { diff --git a/compiler/src/language_server/hints/constant_evaluator.rs b/compiler/src/language_server/hints/constant_evaluator.rs index 5de1ae782..ee48402c6 100644 --- a/compiler/src/language_server/hints/constant_evaluator.rs +++ b/compiler/src/language_server/hints/constant_evaluator.rs @@ -76,7 +76,11 @@ impl ConstantEvaluator { let vm = &self.vms[module]; let mut hints = vec![]; - if let vm::Status::Panicked { reason } = vm.status() { + if let vm::Status::Panicked { + reason, + responsible, + } = vm.status() + { if let Some(hint) = panic_hint(db, module.clone(), vm, reason) { hints.push(hint); } diff --git a/compiler/src/main.rs b/compiler/src/main.rs index 1fded3130..186cb31ff 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -19,7 +19,7 @@ use crate::{ ast_to_hir::AstToHir, cst_to_ast::CstToAst, error::CompilerError, - hir::{self, CollectErrors}, + hir::{self, CollectErrors, Id}, hir_to_lir::HirToLir, rcst_to_cst::RcstToCst, string_to_rcst::StringToRcst, @@ -29,8 +29,8 @@ use crate::{ module::{Module, ModuleKind}, vm::{ context::{DbUseProvider, RunForever, RunLimitedNumberOfInstructions}, - tracer::{DummyTracer, FullTracer}, - Closure, Status, Struct, Vm, + tracer::{DummyTracer, FullTracer, Tracer}, + Closure, ExecutionResult, FiberId, Status, Struct, Vm, }, }; use compiler::lir::Lir; @@ -203,33 +203,21 @@ fn run(options: CandyRunOptions) { warn!("Build failed."); return; }; - let module_closure = Closure::of_module(&db, module.clone()).unwrap(); + // TODO: Optimize the code before running. let path_string = options.file.to_string_lossy(); - info!("Running `{path_string}`."); + debug!("Running `{path_string}`."); + let module_closure = Closure::of_module(&db, module.clone()).unwrap(); let mut tracer = FullTracer::new(); let mut vm = Vm::new(); vm.set_up_for_running_module_closure(module_closure); - loop { - info!("Tree: {:#?}", vm); - match vm.status() { - Status::CanRun => { - debug!("VM still running."); - vm.run( - &mut DbUseProvider { db: &db }, - &mut RunLimitedNumberOfInstructions::new(100000), - &mut tracer, - ); - } - Status::WaitingForOperations => { - todo!("VM can't proceed until some operations complete."); - } - _ => break, - } + vm.run(&mut DbUseProvider { db: &db }, &mut RunForever, &mut tracer); + if let Status::WaitingForOperations = vm.status() { + error!("The module waits on channel operations. Perhaps, the code tried to read from a channel without sending a packet into it."); + // TODO: Show stack traces of all fibers? } - info!("Tree: {:#?}", vm); let result = vm.tear_down(); if options.debug { @@ -237,8 +225,8 @@ fn run(options: CandyRunOptions) { } let (mut heap, exported_definitions): (_, Struct) = match result { - Ok(return_value) => { - info!("The module exports these definitions: {return_value:?}",); + ExecutionResult::Finished(return_value) => { + debug!("The module exports these definitions: {return_value:?}",); let exported = return_value .heap .get(return_value.address) @@ -248,8 +236,16 @@ fn run(options: CandyRunOptions) { .unwrap(); (return_value.heap, exported) } - Err(reason) => { + ExecutionResult::Panicked { + reason, + responsible, + } => { error!("The module panicked because {reason}."); + if let Some(responsible) = responsible { + error!("{responsible} is responsible."); + } else { + error!("Some top-level code panics."); + } error!( "This is the stack trace:\n{}", tracer.format_panic_stack_trace_to_root_fiber(&db) @@ -267,8 +263,8 @@ fn run(options: CandyRunOptions) { } }; - info!("Running main function."); - // TODO: Add environment stuff. + debug!("Running main function."); + // TODO: Add more environment stuff. let mut vm = Vm::new(); let stdout = vm.create_channel(); let environment = { @@ -276,17 +272,18 @@ fn run(options: CandyRunOptions) { let stdout_port = heap.create_send_port(stdout); heap.create_struct([(stdout_symbol, stdout_port)].into_iter().collect()) }; + tracer.in_fiber_tracer(FiberId::root()).call_started( + &heap, + Id::new(module, vec!["main".to_string()]), + main, + vec![environment], + ); vm.set_up_for_running_closure(heap, main, &[environment]); loop { - info!("Tree: {:#?}", vm); match vm.status() { Status::CanRun => { debug!("VM still running."); - vm.run( - &mut DbUseProvider { db: &db }, - &mut RunForever, - &mut DummyTracer, - ); + vm.run(&mut DbUseProvider { db: &db }, &mut RunForever, &mut tracer); // TODO: handle operations } Status::WaitingForOperations => { @@ -306,7 +303,7 @@ fn run(options: CandyRunOptions) { performing_fiber, packet, } => { - info!("Sent to stdout: {}", packet.address.format(&packet.heap)); + info!("{}", packet.address.format(&packet.heap)); vm.complete_send(performing_fiber); } vm::Operation::Receive { .. } => unreachable!(), @@ -314,11 +311,23 @@ fn run(options: CandyRunOptions) { } } } - info!("Tree: {:#?}", vm); match vm.tear_down() { - Ok(return_value) => info!("The main function returned: {return_value:?}"), - Err(reason) => { + ExecutionResult::Finished(return_value) => { + tracer + .in_fiber_tracer(FiberId::root()) + .call_ended(&return_value.heap, return_value.address); + debug!("The main function returned: {return_value:?}"); + } + ExecutionResult::Panicked { + reason, + responsible, + } => { error!("The main function panicked because {reason}."); + if let Some(responsible) = responsible { + error!("{responsible} is responsible."); + } else { + error!("A needs directly in the main function panicks. Perhaps the main functions expects more in the environment."); + } error!( "This is the stack trace:\n{}", tracer.format_panic_stack_trace_to_root_fiber(&db) @@ -335,7 +344,7 @@ async fn fuzz(options: CandyFuzzOptions) { ); if raw_build(module.clone(), false).is_none() { - info!("Build failed."); + warn!("Build failed."); return; } diff --git a/compiler/src/vm/builtin_functions.rs b/compiler/src/vm/builtin_functions.rs index 4272bc3e3..911942f6b 100644 --- a/compiler/src/vm/builtin_functions.rs +++ b/compiler/src/vm/builtin_functions.rs @@ -76,7 +76,7 @@ impl Fiber { Ok(Receive { channel }) => self.status = Status::Receiving { channel }, Ok(Parallel { body }) => self.status = Status::InParallelScope { body }, Ok(Try { body }) => self.status = Status::InTry { body }, - Err(reason) => self.status = Status::Panicked { reason }, + Err(reason) => self.panic(reason), } } } diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index 52611bb71..d06438eda 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -31,13 +31,27 @@ pub struct Fiber { #[derive(Clone, Debug)] pub enum Status { Running, - CreatingChannel { capacity: Capacity }, - Sending { channel: ChannelId, packet: Packet }, - Receiving { channel: ChannelId }, - InParallelScope { body: Pointer }, - InTry { body: Pointer }, + CreatingChannel { + capacity: Capacity, + }, + Sending { + channel: ChannelId, + packet: Packet, + }, + Receiving { + channel: ChannelId, + }, + InParallelScope { + body: Pointer, + }, + InTry { + body: Pointer, + }, Done, - Panicked { reason: String }, + Panicked { + reason: String, + responsible: Option, + }, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -63,6 +77,14 @@ impl InstructionPointer { } } +pub enum ExecutionResult { + Finished(Packet), + Panicked { + reason: String, + responsible: Option, + }, +} + impl Fiber { fn new_with_heap(heap: Heap) -> Self { Self { @@ -97,20 +119,33 @@ impl Fiber { fiber } pub fn new_for_running_module_closure(closure: Closure) -> Self { - assert_eq!(closure.captured.len(), 0, "Called start_module_closure with a closure that is not a module closure (it captures stuff)."); - assert_eq!(closure.num_args, 0, "Called start_module_closure with a closure that is not a module closure (it has arguments)."); + assert_eq!( + closure.captured.len(), + 0, + "closure is not a module closure (it captures stuff)." + ); + assert_eq!( + closure.num_args, 0, + "closure is not a module closure (it has arguments)." + ); let mut heap = Heap::default(); let closure = heap.create_closure(closure); Self::new_for_running_closure(heap, closure, &[]) } - pub fn tear_down(mut self) -> Result { + pub fn tear_down(mut self) -> ExecutionResult { match self.status { - Status::Done => Ok(Packet { + Status::Done => ExecutionResult::Finished(Packet { heap: self.heap, address: self.data_stack.pop().unwrap(), }), - Status::Panicked { reason } => Err(reason), + Status::Panicked { + reason, + responsible, + } => ExecutionResult::Panicked { + reason, + responsible, + }, _ => panic!("Called `tear_down` on a fiber that's still running."), } } @@ -151,9 +186,9 @@ impl Fiber { Err(reason) => self.panic(reason), } } - pub fn complete_try(&mut self, result: Result) { + pub fn complete_try(&mut self, result: ExecutionResult) { let result = match result { - Ok(Packet { + ExecutionResult::Finished(Packet { heap, address: return_value, }) => { @@ -161,9 +196,9 @@ impl Fiber { let return_value = heap.clone_single_to_other_heap(&mut self.heap, return_value); self.heap.create_list(&[ok, return_value]) } - Err(panic_reason) => { + ExecutionResult::Panicked { reason, .. } => { let err = self.heap.create_symbol("Err".to_string()); - let reason = self.heap.create_text(panic_reason); + let reason = self.heap.create_text(reason); self.heap.create_list(&[err, reason]) } }; @@ -175,7 +210,10 @@ impl Fiber { self.data_stack[self.data_stack.len() - 1 - offset as usize] } pub fn panic(&mut self, reason: String) { - self.status = Status::Panicked { reason }; + self.status = Status::Panicked { + reason, + responsible: self.responsible_stack.last().cloned(), + }; } pub fn run( @@ -400,7 +438,7 @@ impl Fiber { "True" => { self.data_stack.push(self.heap.create_nothing()); } - "False" => self.status = Status::Panicked { reason }, + "False" => self.panic(reason), _ => { self.panic("Needs expects True or False as a symbol.".to_string()); } diff --git a/compiler/src/vm/mod.rs b/compiler/src/vm/mod.rs index 51b914b03..9cde03af9 100644 --- a/compiler/src/vm/mod.rs +++ b/compiler/src/vm/mod.rs @@ -17,9 +17,10 @@ use self::{ }; pub use self::{ channel::Packet, - fiber::Fiber, + fiber::{ExecutionResult, Fiber}, heap::{Closure, Heap, Object, Pointer, Struct}, }; +use crate::compiler::hir::Id; use itertools::Itertools; use rand::seq::SliceRandom; use std::{ @@ -28,7 +29,7 @@ use std::{ hash::Hash, marker::PhantomData, }; -use tracing::{info, warn}; +use tracing::{debug, warn}; /// A VM represents a Candy program that thinks it's currently running. Because /// VMs are first-class Rust structs, they enable other code to store "freezed" @@ -124,7 +125,10 @@ pub enum Status { CanRun, WaitingForOperations, Done, - Panicked { reason: String }, + Panicked { + reason: String, + responsible: Option, + }, } impl FiberId { @@ -169,7 +173,7 @@ impl Vm { self.set_up_with_fiber(Fiber::new_for_running_module_closure(closure)) } - pub fn tear_down(mut self) -> Result { + pub fn tear_down(mut self) -> ExecutionResult { let tree = self.fibers.remove(&FiberId::root()).unwrap(); let single = tree.into_single().unwrap(); single.fiber.tear_down() @@ -189,8 +193,12 @@ impl Vm { | fiber::Status::InParallelScope { .. } | fiber::Status::InTry { .. } => unreachable!(), fiber::Status::Done => Status::Done, - fiber::Status::Panicked { reason } => Status::Panicked { + fiber::Status::Panicked { + reason, + responsible, + } => Status::Panicked { reason: reason.clone(), + responsible: responsible.clone(), }, }, FiberTree::Parallel(Parallel { children, .. }) => { @@ -379,11 +387,14 @@ impl Vm { false } fiber::Status::Done => { - info!("A fiber is done."); + debug!("A fiber is done."); tracer.fiber_done(fiber_id); true } - fiber::Status::Panicked { reason } => { + fiber::Status::Panicked { + reason, + responsible, + } => { warn!("A fiber panicked because {reason}."); tracer.fiber_panicked(fiber_id, None); true @@ -408,7 +419,7 @@ impl Vm { let child = parallel.children.remove(&fiber_id).unwrap(); match result { - Ok(return_value) => { + ExecutionResult::Finished(return_value) => { let is_finished = parallel.children.is_empty(); match child { ChildKind::InitialChild => { @@ -423,9 +434,10 @@ impl Vm { self.finish_parallel(tracer, parent, Some(fiber_id), Ok(())) } } - Err(panic_reason) => { - self.finish_parallel(tracer, parent, Some(fiber_id), Err(panic_reason)) - } + ExecutionResult::Panicked { + reason, + responsible, + } => self.finish_parallel(tracer, parent, Some(fiber_id), Err(reason)), } } FiberTree::Try(Try { .. }) => { @@ -550,7 +562,7 @@ impl Vm { }, ), Channel::Nursery(parent_id) => { - info!("Nursery received packet {:?}", packet); + debug!("Nursery received packet {:?}", packet); let parent_id = *parent_id; match Self::parse_spawn_packet(packet) { diff --git a/compiler/src/vm/tracer/full_trace.rs b/compiler/src/vm/tracer/full_trace.rs deleted file mode 100644 index d275fabe2..000000000 --- a/compiler/src/vm/tracer/full_trace.rs +++ /dev/null @@ -1,201 +0,0 @@ -use super::{ - super::heap::{ChannelId, Pointer}, - FiberId, Heap, -}; -use crate::{ - compiler::{ast_to_hir::AstToHir, cst::CstDb, hir::Id}, - database::Database, - language_server::utils::LspPositionConversion, - module::Module, -}; -use itertools::Itertools; -use std::{collections::HashMap, time::Instant}; -use tracing::error; - -// Full traces are a computed tree view of the whole execution. - -pub struct Trace { - #[allow(dead_code)] - start: Instant, - - #[allow(dead_code)] - end: Instant, - - data: TraceData, -} -pub enum TraceData { - Call { - id: Id, - closure: Pointer, - args: Vec, - inner: Vec, - result: TraceResult, - }, - Needs { - id: Id, - condition: Pointer, - reason: Pointer, - result: TraceResult, - }, - Module { - module: Module, - inner: Vec, - result: TraceResult, - }, -} -pub enum TraceResult { - Returned(Pointer), - - #[allow(dead_code)] - Panicked(Pointer), - - #[allow(dead_code)] - Canceled, -} - -impl FullTracer { - pub fn full_trace(&self) -> Trace { - let mut stacks: HashMap> = HashMap::new(); - for TimedEvent { when, event } in &self.events { - match &event { - Event::FiberCreated { fiber } => { - stacks.insert( - *fiber, - vec![Span { - start: when.clone(), - data: None, - inner: vec![], - }], - ); - } - Event::InFiber { fiber, event } => { - let stack = stacks.get_mut(fiber).unwrap(); - match event { - InFiberEvent::ModuleStarted { module } => todo!(), - InFiberEvent::ModuleEnded { export_map } => todo!(), - InFiberEvent::CallStarted { id, closure, args } => stack.push(Span { - start: when, - data: Some(StackEntry::Call { - id: id.clone(), - closure: *closure, - args: args.clone(), - }), - inner: vec![], - }), - InFiberEvent::CallEnded { return_value } => { - let span = stack.pop().unwrap(); - let (id, closure, args) = match span.data.unwrap() { - StackEntry::Call { id, closure, args } => (id, closure, args), - _ => unreachable!(), - }; - stack.last_mut().unwrap().inner.push(Trace { - start: span.start, - end: event.when, - data: TraceData::Call { - id, - closure, - args, - inner: span.inner, - result: TraceResult::Returned(*return_value), - }, - }); - } - InFiberEvent::ModuleStarted { module } => { - stack.push(Span { - start: event.when, - data: Some(StackEntry::Module { - module: module.clone(), - }), - inner: vec![], - }); - } - InFiberEvent::ModuleEnded { export_map } => { - let span = stack.pop().unwrap(); - let module = match span.data.unwrap() { - StackEntry::Module { module } => module, - _ => unreachable!(), - }; - stack.last_mut().unwrap().inner.push(Trace { - start: span.start, - end: event.when, - data: TraceData::Module { - module, - inner: span.inner, - result: TraceResult::Returned(*export_map), - }, - }); - } - _ => {} - } - } - } - } - stacks - } -} - -struct Span { - start: Instant, - data: Option, - inner: Vec, -} - -impl TraceResult { - fn format(&self, heap: &Heap) -> String { - match self { - TraceResult::Returned(return_value) => return_value.format(heap), - TraceResult::Panicked(panic_value) => { - format!("panicked with {}", panic_value.format(heap)) - } - TraceResult::Canceled => "canceled".to_string(), - } - } -} - -impl Trace { - pub fn format(&self, heap: &Heap) -> String { - let mut lines = vec![]; - match &self.data { - TraceData::Call { - id, - args, - inner, - result, - .. - } => { - lines.push(format!( - "call {id} {} = {}", - args.iter().map(|arg| arg.format(heap)).join(" "), - result.format(heap), - )); - for trace in inner { - lines.extend(trace.format(heap).lines().map(|line| format!(" {line}"))); - } - } - TraceData::Needs { - condition, - reason, - result, - .. - } => { - lines.push(format!( - "needs {} {} = {}", - condition.format(heap), - reason.format(heap), - result.format(heap), - )); - } - TraceData::Module { - module, - inner, - result, - } => { - lines.push(format!("{module} = {}", result.format(heap))); - for trace in inner { - lines.extend(trace.format(heap).lines().map(|line| format!(" {line}"))); - } - } - } - lines.join("\n") - } -} diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index 120ecde7f..33e8d449d 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -1,4 +1,3 @@ -// mod full_trace; pub mod stack_trace; use super::{ From 80fde35e7bf8d1e4fc143ecae56127487f74c65e Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 10 Oct 2022 22:10:47 +0200 Subject: [PATCH 11/44] Adapt fuzzing to new tracing --- compiler/src/fuzzer/fuzzer.rs | 3 +- compiler/src/fuzzer/mod.rs | 28 +++---- compiler/src/fuzzer/utils.rs | 107 ++++++++++++++++---------- compiler/src/vm/mod.rs | 4 +- compiler/src/vm/tracer/stack_trace.rs | 2 + 5 files changed, 86 insertions(+), 58 deletions(-) diff --git a/compiler/src/fuzzer/fuzzer.rs b/compiler/src/fuzzer/fuzzer.rs index ad5b75a0e..a7df918c8 100644 --- a/compiler/src/fuzzer/fuzzer.rs +++ b/compiler/src/fuzzer/fuzzer.rs @@ -1,4 +1,4 @@ -use super::{generator::generate_n_values, utils::did_need_in_closure_cause_panic}; +use super::generator::generate_n_values; use crate::{ compiler::hir, database::Database, @@ -115,7 +115,6 @@ impl Fuzzer { // If a `needs` directly inside the tested closure was not // satisfied, then the panic is not closure's fault, but our // fault. - let result = vm.tear_down(); let is_our_fault = responsible.is_none(); if is_our_fault { Status::new_fuzzing_attempt(&self.closure_heap, self.closure) diff --git a/compiler/src/fuzzer/mod.rs b/compiler/src/fuzzer/mod.rs index a4606a14f..fb0ccc892 100644 --- a/compiler/src/fuzzer/mod.rs +++ b/compiler/src/fuzzer/mod.rs @@ -2,27 +2,30 @@ mod fuzzer; mod generator; mod utils; -pub use self::fuzzer::{Fuzzer, Status}; +pub use self::{ + fuzzer::{Fuzzer, Status}, + utils::FuzzablesFinder, +}; use crate::{ compiler::hir::Id, database::Database, module::Module, vm::{ context::{DbUseProvider, RunForever, RunLimitedNumberOfInstructions}, - tracer::DummyTracer, Closure, Heap, Pointer, Vm, }, }; use itertools::Itertools; -use tracing::info; +use tracing::{error, info}; pub async fn fuzz(db: &Database, module: Module) { let (fuzzables_heap, fuzzables): (Heap, Vec<(Id, Pointer)>) = { + let mut tracer = FuzzablesFinder::new(); let mut vm = Vm::new(); vm.set_up_for_running_module_closure(Closure::of_module(db, module.clone()).unwrap()); - vm.run(&mut DbUseProvider { db }, &mut RunForever, &mut DummyTracer); + vm.run(&mut DbUseProvider { db }, &mut RunForever, &mut tracer); let result = vm.tear_down(); - (todo!(), todo!()) + (tracer.heap, tracer.fuzzables) }; info!( @@ -44,17 +47,16 @@ pub async fn fuzz(db: &Database, module: Module) { reason, tracer, } => { - info!("The fuzzer discovered an input that crashes {id}:"); - info!( + error!("The fuzzer discovered an input that crashes {id}:"); + error!( "Calling `{id} {}` doesn't work because {reason}.", arguments.iter().map(|arg| format!("{arg:?}")).join(" "), ); - info!("This was the stack trace:"); - // tracer.dump_stack_trace(db); - todo!(); - - // module.dump_associated_debug_file("trace", &tracer.full_trace().format(heap)); - todo!(); + error!("Events:\n {tracer:?}"); + error!( + "This is the stack trace:\n{}", + tracer.format_panic_stack_trace_to_root_fiber(db) + ); } } } diff --git a/compiler/src/fuzzer/utils.rs b/compiler/src/fuzzer/utils.rs index 7d94e6337..8015224ef 100644 --- a/compiler/src/fuzzer/utils.rs +++ b/compiler/src/fuzzer/utils.rs @@ -1,47 +1,72 @@ use crate::{ - compiler::hir::{self, Expression, HirDb, Lambda}, - database::Database, - vm::tracer::{FullTracer, Tracer}, + compiler::hir::Id, + module::Module, + vm::{ + tracer::{InFiberTracer, Tracer}, + ChannelId, FiberId, Heap, Pointer, + }, }; +use std::collections::HashMap; -pub fn did_need_in_closure_cause_panic(db: &Database, closure_id: &hir::Id) -> bool { - todo!(); - // let entry = if let Some(entry) = tracer.events.last() { - // entry - // } else { - // // The only way there's no trace log before the panic is when there's an - // // error from an earlier compilation stage that got lowered into the - // // LIR. That's also definitely the fault of the function. - // return false; - // }; - // if let Event::InFiber { - // event: InFiberEvent::NeedsStarted { id, .. }, - // .. - // } = &entry.data - // { - // let mut id = id.parent().unwrap(); - // loop { - // if &id == closure_id { - // return true; - // } +pub struct FuzzablesFinder { + pub fuzzables: Vec<(Id, Pointer)>, + pub heap: Heap, + transferred_objects: HashMap>, +} +impl FuzzablesFinder { + pub fn new() -> Self { + Self { + fuzzables: vec![], + heap: Heap::default(), + transferred_objects: HashMap::new(), + } + } +} +impl Tracer for FuzzablesFinder { + fn fiber_created(&mut self, fiber: FiberId) {} + fn fiber_done(&mut self, fiber: FiberId) {} + fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option) {} + fn fiber_canceled(&mut self, fiber: FiberId) {} + fn fiber_execution_started(&mut self, fiber: FiberId) {} + fn fiber_execution_ended(&mut self, fiber: FiberId) {} + fn channel_created(&mut self, channel: ChannelId) {} + fn sent_to_channel(&mut self, value: Pointer, from: FiberId, to: ChannelId) {} + fn received_from_channel(&mut self, value: Pointer, from: ChannelId, to: FiberId) {} - // match db - // .find_expression(id.clone()) - // .expect("Parent of a `needs` call is a parameter.") - // { - // Expression::Lambda(Lambda { fuzzable, .. }) => { - // if fuzzable { - // return false; // The needs is in a different fuzzable lambda. - // } - // } - // _ => panic!("Only lambdas can be the parent of a `needs` call."), - // }; + fn in_fiber_tracer<'a>(&'a mut self, fiber: FiberId) -> Box + 'a> + where + Self: 'a, + { + Box::new(InFiberFuzzablesFinder { + tracer: self, + fiber, + }) + } +} +pub struct InFiberFuzzablesFinder<'a> { + tracer: &'a mut FuzzablesFinder, + fiber: FiberId, +} +impl<'a> InFiberTracer<'a> for InFiberFuzzablesFinder<'a> { + fn module_started(&mut self, _module: Module) {} + fn module_ended(&mut self, _heap: &Heap, _export_map: Pointer) {} + fn value_evaluated(&mut self, _heap: &Heap, _id: Id, _value: Pointer) {} + fn call_started(&mut self, _heap: &Heap, _id: Id, _closure: Pointer, _args: Vec) {} + fn call_ended(&mut self, _heap: &Heap, _return_value: Pointer) {} + fn needs_started(&mut self, _heap: &Heap, _id: Id, _condition: Pointer, _reason: Pointer) {} + fn needs_ended(&mut self) {} - // match id.parent() { - // Some(parent_id) => id = parent_id, - // None => return false, - // } - // } - // } - false + fn found_fuzzable_closure(&mut self, heap: &Heap, id: Id, closure: Pointer) { + let address_map = self + .tracer + .transferred_objects + .entry(self.fiber) + .or_insert_with(HashMap::new); + let address = heap.clone_single_to_other_heap_with_existing_mapping( + &mut self.tracer.heap, + closure, + address_map, + ); + self.tracer.fuzzables.push((id, address)); + } } diff --git a/compiler/src/vm/mod.rs b/compiler/src/vm/mod.rs index 9cde03af9..026823acf 100644 --- a/compiler/src/vm/mod.rs +++ b/compiler/src/vm/mod.rs @@ -12,13 +12,13 @@ use self::{ CombiningExecutionController, ExecutionController, RunLimitedNumberOfInstructions, UseProvider, }, - heap::{ChannelId, SendPort}, + heap::SendPort, tracer::Tracer, }; pub use self::{ channel::Packet, fiber::{ExecutionResult, Fiber}, - heap::{Closure, Heap, Object, Pointer, Struct}, + heap::{ChannelId, Closure, Heap, Object, Pointer, Struct}, }; use crate::compiler::hir::Id; use itertools::Itertools; diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs index 75878c98a..29ecaec5f 100644 --- a/compiler/src/vm/tracer/stack_trace.rs +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -11,6 +11,7 @@ use crate::{ }; use itertools::Itertools; use std::collections::HashMap; +use tracing::debug; // Stack traces are a reduced view of the tracing state that represent the stack // trace at a given moment in time. @@ -159,6 +160,7 @@ impl FullTracer { } let stack_traces = self.stack_traces(); + debug!("Stack traces: {:?}", stack_traces.keys().collect_vec()); panicking_fiber_chain .into_iter() .rev() From 9de29ee59500a2c86e8af7efa3fa117d2ff07a61 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Thu, 13 Oct 2022 19:23:11 +0200 Subject: [PATCH 12/44] Update todos --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7ced79e64..081492b71 100644 --- a/README.md +++ b/README.md @@ -119,19 +119,21 @@ Major milestones: - casing of module names - fix fault attribution -- rearchitect tracing - new name? - add caching while compile-time evaluating code -- tags? +- tags - pattern matching - pipe operator +- add CI +- add tests +- add a more lightweight tracer that only tracks stack traces - text interpolation -- eliminate common subtrees -- inline functions +- optimize: eliminate common subtrees +- optimize: inline functions - minimize inputs found through fuzzing - fuzz parser - remove builtinPrint -- tail call optimization +- optimize: tail call optimization - parse function declaration with doc comment but no code - tracing visualization - distinguish packages from normal modules From 8bf332114b2e27eeff163a09030f664669f16ca7 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Thu, 13 Oct 2022 19:24:21 +0200 Subject: [PATCH 13/44] Print to stdout using channels --- packages/Benchmark.candy | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/Benchmark.candy b/packages/Benchmark.candy index 8642a9297..5af9ebb66 100644 --- a/packages/Benchmark.candy +++ b/packages/Benchmark.candy @@ -36,3 +36,4 @@ core.parallel { nursery -> main environment := ✨.print "Hello, world!" + core.channel.send environment.stdout "Hello, world!" From 7ddf44cdf8e6f9c78d691a8d82e4278f052a7571 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Fri, 14 Oct 2022 00:01:41 +0200 Subject: [PATCH 14/44] Fix ids --- compiler/src/vm/ids.rs | 10 ++++++++++ compiler/src/vm/tracer/mod.rs | 5 +---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/src/vm/ids.rs b/compiler/src/vm/ids.rs index 4148211a7..13731d185 100644 --- a/compiler/src/vm/ids.rs +++ b/compiler/src/vm/ids.rs @@ -20,6 +20,7 @@ impl IdGenerator { } pub trait CountableId { fn from_usize(id: usize) -> Self; + fn to_usize(&self) -> usize; } #[derive(Clone, Copy, PartialEq, Eq, Hash)] @@ -28,6 +29,9 @@ impl CountableId for FiberId { fn from_usize(id: usize) -> Self { Self(id) } + fn to_usize(&self) -> usize { + self.0 + } } impl fmt::Debug for FiberId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -42,6 +46,9 @@ impl CountableId for ChannelId { fn from_usize(id: usize) -> Self { Self(id) } + fn to_usize(&self) -> usize { + self.0 + } } impl fmt::Debug for ChannelId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -55,6 +62,9 @@ impl CountableId for OperationId { fn from_usize(id: usize) -> Self { Self(id) } + fn to_usize(&self) -> usize { + self.0 + } } impl fmt::Debug for OperationId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index 33e8d449d..5282af97b 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -1,9 +1,6 @@ pub mod stack_trace; -use super::{ - heap::{ChannelId, Pointer}, - FiberId, Heap, -}; +use super::{heap::Pointer, ChannelId, FiberId, Heap}; use crate::{compiler::hir::Id, module::Module}; use itertools::Itertools; use std::{collections::HashMap, fmt, time::Instant}; From 6c07c6fcb5a2a6d81b3b042dd9a1c15cb77e262d Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 17 Oct 2022 18:11:34 +0200 Subject: [PATCH 15/44] Update fuzzing to responsibilites --- compiler/src/fuzzer/fuzzer.rs | 11 +++----- compiler/src/fuzzer/mod.rs | 6 ++--- compiler/src/fuzzer/utils.rs | 18 +++++++------- compiler/src/vm/fiber.rs | 13 +++++++--- compiler/src/vm/mod.rs | 47 ++++++++++++++++++----------------- compiler/src/vm/tracer/mod.rs | 6 ++--- 6 files changed, 52 insertions(+), 49 deletions(-) diff --git a/compiler/src/fuzzer/fuzzer.rs b/compiler/src/fuzzer/fuzzer.rs index a7df918c8..e3ec39614 100644 --- a/compiler/src/fuzzer/fuzzer.rs +++ b/compiler/src/fuzzer/fuzzer.rs @@ -1,11 +1,10 @@ use super::generator::generate_n_values; use crate::{ compiler::hir, - database::Database, vm::{ self, context::{ExecutionController, UseProvider}, - tracer::{DummyTracer, FullTracer}, + tracer::FullTracer, Closure, Heap, Packet, Pointer, Vm, }, }; @@ -83,7 +82,6 @@ impl Fuzzer { pub fn run( &mut self, - db: &Database, use_provider: &mut U, execution_controller: &mut E, ) { @@ -91,21 +89,20 @@ impl Fuzzer { while matches!(status, Status::StillFuzzing { .. }) && execution_controller.should_continue_running() { - status = self.map_status(status, db, use_provider, execution_controller); + status = self.map_status(status, use_provider, execution_controller); } self.status = Some(status); } fn map_status( &self, status: Status, - db: &Database, use_provider: &mut U, execution_controller: &mut E, ) -> Status { match status { - Status::StillFuzzing { mut vm, arguments, tracer } => match vm.status() { + Status::StillFuzzing { mut vm, arguments, mut tracer } => match vm.status() { vm::Status::CanRun => { - vm.run(use_provider, execution_controller, &mut DummyTracer); + vm.run(use_provider, execution_controller, &mut tracer); Status::StillFuzzing { vm, arguments, tracer } } vm::Status::WaitingForOperations => panic!("Fuzzing should not have to wait on channel operations because arguments were not channels."), diff --git a/compiler/src/fuzzer/mod.rs b/compiler/src/fuzzer/mod.rs index fb0ccc892..3ceaa73ad 100644 --- a/compiler/src/fuzzer/mod.rs +++ b/compiler/src/fuzzer/mod.rs @@ -22,9 +22,8 @@ pub async fn fuzz(db: &Database, module: Module) { let (fuzzables_heap, fuzzables): (Heap, Vec<(Id, Pointer)>) = { let mut tracer = FuzzablesFinder::new(); let mut vm = Vm::new(); - vm.set_up_for_running_module_closure(Closure::of_module(db, module.clone()).unwrap()); + vm.set_up_for_running_module_closure(Closure::of_module(db, module).unwrap()); vm.run(&mut DbUseProvider { db }, &mut RunForever, &mut tracer); - let result = vm.tear_down(); (tracer.heap, tracer.fuzzables) }; @@ -34,9 +33,9 @@ pub async fn fuzz(db: &Database, module: Module) { ); for (id, closure) in fuzzables { + info!("Fuzzing {id}"); let mut fuzzer = Fuzzer::new(&fuzzables_heap, closure, id.clone()); fuzzer.run( - db, &mut DbUseProvider { db }, &mut RunLimitedNumberOfInstructions::new(1000), ); @@ -52,7 +51,6 @@ pub async fn fuzz(db: &Database, module: Module) { "Calling `{id} {}` doesn't work because {reason}.", arguments.iter().map(|arg| format!("{arg:?}")).join(" "), ); - error!("Events:\n {tracer:?}"); error!( "This is the stack trace:\n{}", tracer.format_panic_stack_trace_to_root_fiber(db) diff --git a/compiler/src/fuzzer/utils.rs b/compiler/src/fuzzer/utils.rs index 8015224ef..d30ee4499 100644 --- a/compiler/src/fuzzer/utils.rs +++ b/compiler/src/fuzzer/utils.rs @@ -23,15 +23,15 @@ impl FuzzablesFinder { } } impl Tracer for FuzzablesFinder { - fn fiber_created(&mut self, fiber: FiberId) {} - fn fiber_done(&mut self, fiber: FiberId) {} - fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option) {} - fn fiber_canceled(&mut self, fiber: FiberId) {} - fn fiber_execution_started(&mut self, fiber: FiberId) {} - fn fiber_execution_ended(&mut self, fiber: FiberId) {} - fn channel_created(&mut self, channel: ChannelId) {} - fn sent_to_channel(&mut self, value: Pointer, from: FiberId, to: ChannelId) {} - fn received_from_channel(&mut self, value: Pointer, from: ChannelId, to: FiberId) {} + fn fiber_created(&mut self, _fiber: FiberId) {} + fn fiber_done(&mut self, _fiber: FiberId) {} + fn fiber_panicked(&mut self, _fiber: FiberId, _panicked_child: Option) {} + fn fiber_canceled(&mut self, _fiber: FiberId) {} + fn fiber_execution_started(&mut self, _fiber: FiberId) {} + fn fiber_execution_ended(&mut self, _fiber: FiberId) {} + fn channel_created(&mut self, _channel: ChannelId) {} + fn sent_to_channel(&mut self, _value: Pointer, _from: FiberId, _to: ChannelId) {} + fn received_from_channel(&mut self, _value: Pointer, _from: ChannelId, _to: FiberId) {} fn in_fiber_tracer<'a>(&'a mut self, fiber: FiberId) -> Box + 'a> where diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index b5c39975c..14afedb39 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -250,6 +250,11 @@ impl Fiber { let instruction = current_body[self.next_instruction.instruction].clone(); if TRACE { + trace!( + "Instruction pointer: {}:{}", + self.next_instruction.closure, + self.next_instruction.instruction + ); trace!( "Data stack: {}", self.data_stack @@ -265,9 +270,11 @@ impl Fiber { .join(", ") ); trace!( - "Instruction pointer: {}:{}", - self.next_instruction.closure, - self.next_instruction.instruction + "Responsible stack: {}", + self.responsible_stack + .iter() + .map(|responsible| format!("{}", responsible)) + .join(", ") ); trace!("Heap: {:?}", self.heap); trace!("Running instruction: {instruction:?}"); diff --git a/compiler/src/vm/mod.rs b/compiler/src/vm/mod.rs index 740179f7c..37b7c1aa1 100644 --- a/compiler/src/vm/mod.rs +++ b/compiler/src/vm/mod.rs @@ -7,21 +7,22 @@ mod ids; pub mod tracer; mod use_module; +pub use self::{ + channel::Packet, + fiber::{ExecutionResult, Fiber}, + heap::{Closure, Heap, Object, Pointer, Struct}, + ids::{ChannelId, FiberId, OperationId}, +}; use self::{ - channel::{Channel, Completer, Packet, Performer}, + channel::{Channel, Completer, Performer}, context::{ CombiningExecutionController, ExecutionController, RunLimitedNumberOfInstructions, UseProvider, }, heap::SendPort, - ids::{CountableId, FiberId, IdGenerator}, + ids::{CountableId, IdGenerator}, tracer::Tracer, }; -pub use self::{ - fiber::{ExecutionResult, Fiber}, - heap::{Closure, Heap, Object, Pointer, Struct}, - ids::{ChannelId, OperationId}, -}; use crate::compiler::hir::Id; use itertools::Itertools; use rand::seq::SliceRandom; @@ -30,7 +31,6 @@ use std::{ fmt, hash::Hash, }; -use tracing::{debug, warn}; /// A VM represents a Candy program that thinks it's currently running. Because /// VMs are first-class Rust structs, they enable other code to store "freezed" @@ -156,7 +156,7 @@ impl Vm { closure: Pointer, arguments: &[Pointer], ) { - self.set_up_with_fiber(Fiber::new_for_running_closure(heap, closure, arguments)) + self.set_up_with_fiber(Fiber::new_for_running_closure(heap, closure, arguments)); } pub fn set_up_for_running_module_closure(&mut self, closure: Closure) { self.set_up_with_fiber(Fiber::new_for_running_module_closure(closure)) @@ -233,7 +233,7 @@ impl Vm { operation_id } - pub fn receive(&mut self, tracer: &mut dyn Tracer, channel: ChannelId) -> OperationId { + pub fn receive(&mut self, channel: ChannelId) -> OperationId { let operation_id = self.operation_id_generator.generate(); self.receive_from_channel(Performer::External(operation_id), channel); operation_id @@ -375,15 +375,10 @@ impl Vm { false } fiber::Status::Done => { - debug!("A fiber is done."); tracer.fiber_done(fiber_id); true } - fiber::Status::Panicked { - reason, - responsible, - } => { - warn!("A fiber panicked because {reason}."); + fiber::Status::Panicked { .. } => { tracer.fiber_panicked(fiber_id, None); true } @@ -422,13 +417,20 @@ impl Vm { } if is_finished { - self.finish_parallel(tracer, parent, Performer(fiber_id), Ok(())) + self.finish_parallel( + tracer, + parent, + Performer::Fiber(fiber_id), + Ok(()), + ) } } - ExecutionResult::Panicked { - reason, - responsible, - } => self.finish_parallel(tracer, parent, Some(fiber_id), Err(reason)), + ExecutionResult::Panicked { reason, .. } => self.finish_parallel( + tracer, + parent, + Performer::Fiber(fiber_id), + Err(reason), + ), } } FiberTree::Try(Try { .. }) => { @@ -555,7 +557,6 @@ impl Vm { channel.send(&mut completer, performer, packet); } ChannelLike::Nursery(parent_id) => { - debug!("Nursery received packet {:?}", packet); let parent_id = *parent_id; match Self::parse_spawn_packet(packet) { @@ -582,7 +583,7 @@ impl Vm { None => self.finish_parallel( tracer, parent_id, - performer, + performer.clone(), Err("a nursery received an invalid message".to_string()), ), } diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index 5282af97b..88f2ecc24 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -71,13 +71,13 @@ impl<'a> InFiberTracer<'a> for DummyInFiberTracer { #[derive(Clone)] pub struct FullTracer { pub events: Vec, - heap: Heap, + pub heap: Heap, transferred_objects: HashMap>, } #[derive(Clone)] pub struct TimedEvent { - when: Instant, - event: Event, + pub when: Instant, + pub event: Event, } #[derive(Clone)] pub enum Event { From 80f7b7c09227657ad31f4c1a6579badebb7bfb2c Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 17 Oct 2022 18:11:45 +0200 Subject: [PATCH 16/44] Fix responsibilities of curly closures --- compiler/src/vm/fiber.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index 14afedb39..505cab212 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -341,9 +341,9 @@ impl Fiber { num_args, body, responsible: if is_curly { - None - } else { self.responsible_stack.last().cloned() + } else { + None }, }); self.data_stack.push(address); From 42673b90e49ac06cb554ddf86f71eef3b0767685 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 17 Oct 2022 18:12:07 +0200 Subject: [PATCH 17/44] Fix language server --- .../hints/constant_evaluator.rs | 96 +++++++++++-------- compiler/src/language_server/hints/fuzzer.rs | 61 ++++++------ 2 files changed, 90 insertions(+), 67 deletions(-) diff --git a/compiler/src/language_server/hints/constant_evaluator.rs b/compiler/src/language_server/hints/constant_evaluator.rs index d0e002d86..0043c8f65 100644 --- a/compiler/src/language_server/hints/constant_evaluator.rs +++ b/compiler/src/language_server/hints/constant_evaluator.rs @@ -12,8 +12,8 @@ use crate::{ vm::{ self, context::{DbUseProvider, RunLimitedNumberOfInstructions}, - tracer::{stack_trace::StackEntry, DummyTracer, Event, FullTracer, TimedEvent}, - Closure, Heap, Pointer, Vm, + tracer::{stack_trace::StackEntry, Event, FullTracer, InFiberEvent, TimedEvent}, + Closure, FiberId, Heap, Pointer, Vm, }, }; use itertools::Itertools; @@ -23,38 +23,43 @@ use tracing::{span, trace, Level}; #[derive(Default)] pub struct ConstantEvaluator { - vms: HashMap, + evaluators: HashMap, +} +struct Evaluator { + tracer: FullTracer, + vm: Vm, } impl ConstantEvaluator { pub fn update_module(&mut self, db: &Database, module: Module) { + let tracer = FullTracer::new(); let mut vm = Vm::new(); vm.set_up_for_running_module_closure(Closure::of_module(db, module.clone()).unwrap()); - self.vms.insert(module, vm); + self.evaluators.insert(module, Evaluator { tracer, vm }); } pub fn remove_module(&mut self, module: Module) { - self.vms.remove(&module).unwrap(); + self.evaluators.remove(&module).unwrap(); } pub fn run(&mut self, db: &Database) -> Option { - let num_vms = self.vms.len(); - let mut running_vms = self - .vms + let num_evaluators = self.evaluators.len(); + let mut running_evaluators = self + .evaluators .iter_mut() - .filter(|(_, vm)| matches!(vm.status(), vm::Status::CanRun)) + .filter(|(_, evaluator)| matches!(evaluator.vm.status(), vm::Status::CanRun)) .collect_vec(); trace!( "Constant evaluator running. {} running VMs, {} in total.", - running_vms.len(), - num_vms, + running_evaluators.len(), + num_evaluators, ); - if let Some((module, vm)) = running_vms.choose_mut(&mut thread_rng()) { - vm.run( + if let Some((module, evaluator)) = running_evaluators.choose_mut(&mut thread_rng()) { + evaluator.vm.run( &mut DbUseProvider { db }, &mut RunLimitedNumberOfInstructions::new(500), - &mut DummyTracer, + &mut evaluator.tracer, ); Some(module.clone()) } else { @@ -63,34 +68,38 @@ impl ConstantEvaluator { } pub fn get_fuzzable_closures(&self, module: &Module) -> (Heap, Vec<(Id, Pointer)>) { - let vm = &self.vms[module]; - let result = vm.clone().tear_down(); - // (heap, fuzzable_closures) - todo!() + let evaluator = &self.evaluators[module]; + let fuzzable_closures = evaluator + .tracer + .events + .iter() + .filter_map(|event| match &event.event { + Event::InFiber { + event: InFiberEvent::FoundFuzzableClosure { id, closure }, + .. + } => Some((id.clone(), *closure)), + _ => None, + }) + .collect(); + (evaluator.tracer.heap.clone(), fuzzable_closures) } pub fn get_hints(&self, db: &Database, module: &Module) -> Vec { let span = span!(Level::DEBUG, "Calculating hints for {module}"); let _enter = span.enter(); - let vm = &self.vms[module]; + let evaluator = &self.evaluators[module]; let mut hints = vec![]; - if let vm::Status::Panicked { - reason, - responsible, - } = vm.status() - { - if let Some(hint) = panic_hint(db, module.clone(), vm, reason) { + // TODO: Think about how to highlight the responsible piece of code. + if let vm::Status::Panicked { reason, .. } = evaluator.vm.status() { + if let Some(hint) = panic_hint(db, module.clone(), evaluator, reason) { hints.push(hint); } }; - // let TearDownResult { heap, tracer, .. } = vm.clone().tear_down(); - let heap: Heap = todo!(); - let tracer: FullTracer = todo!(); - for TimedEvent { event, .. } in &tracer.events { - let Event::ValueEvaluated { id, value } = event else { continue; }; + for TimedEvent { event, .. } in &evaluator.tracer.events { + let Event::InFiber { event: InFiberEvent::ValueEvaluated { id, value }, .. } = event else { continue; }; if &id.module != module { continue; @@ -113,7 +122,7 @@ impl ConstantEvaluator { hints.push(Hint { kind: HintKind::Value, - text: value.format(&heap), + text: value.format(&evaluator.tracer.heap), position: id_to_end_of_line(db, id.clone()).unwrap(), }); } @@ -122,14 +131,17 @@ impl ConstantEvaluator { } } -fn panic_hint(db: &Database, module: Module, vm: &Vm, reason: String) -> Option { +fn panic_hint( + db: &Database, + module: Module, + evaluator: &Evaluator, + reason: String, +) -> Option { // We want to show the hint at the last call site still inside the current // module. If there is no call site in this module, then the panic results // from a compiler error in a previous stage which is already reported. - let heap: Heap = todo!(); // vm.clone().tear_down(); - let tracer: FullTracer = todo!(); - // let stack = tracer.stack_trace(); - let stack: Vec = todo!(); + let stack_traces = evaluator.tracer.stack_traces(); + let stack = stack_traces.get(&FiberId::root()).unwrap(); if stack.len() == 1 { // The stack only contains an `InModule` entry. This indicates an error // during compilation resulting in a top-level error instruction. @@ -152,8 +164,10 @@ fn panic_hint(db: &Database, module: Module, vm: &Vm, reason: String) -> Option< id, format!( "{} {}", - closure.format(&heap), - args.iter().map(|arg| arg.format(&heap)).join(" ") + closure.format(&evaluator.tracer.heap), + args.iter() + .map(|arg| arg.format(&evaluator.tracer.heap)) + .join(" ") ), ), StackEntry::Needs { @@ -162,7 +176,11 @@ fn panic_hint(db: &Database, module: Module, vm: &Vm, reason: String) -> Option< reason, } => ( id, - format!("needs {} {}", condition.format(&heap), reason.format(&heap)), + format!( + "needs {} {}", + condition.format(&evaluator.tracer.heap), + reason.format(&evaluator.tracer.heap) + ), ), _ => unreachable!(), }; diff --git a/compiler/src/language_server/hints/fuzzer.rs b/compiler/src/language_server/hints/fuzzer.rs index 677197b7f..84832b302 100644 --- a/compiler/src/language_server/hints/fuzzer.rs +++ b/compiler/src/language_server/hints/fuzzer.rs @@ -9,6 +9,7 @@ use crate::{ module::Module, vm::{ context::{DbUseProvider, RunLimitedNumberOfInstructions}, + tracer::{Event, InFiberEvent}, Heap, Pointer, }, }; @@ -54,7 +55,6 @@ impl FuzzerManager { let fuzzer = running_fuzzers.choose_mut(&mut thread_rng())?; fuzzer.run( - db, &mut DbUseProvider { db }, &mut RunLimitedNumberOfInstructions::new(100), ); @@ -110,13 +110,16 @@ impl FuzzerManager { .rev() // Find the innermost panicking call that is in the // function. - .find(|entry| { - let innermost_panicking_call_id = todo!(); - // match &entry.event { - // EventData::CallStarted { id, .. } => id, - // EventData::NeedsStarted { id, .. } => id, - // _ => return false, - // }; + .filter_map(|event| match &event.event { + Event::InFiber { event, .. } => Some(event), + _ => None, + }) + .find(|event| { + let innermost_panicking_call_id = match &event { + InFiberEvent::CallStarted { id, .. } => id, + InFiberEvent::NeedsStarted { id, .. } => id, + _ => return false, + }; id.is_same_module_and_any_parent_of(innermost_panicking_call_id) && db.hir_to_cst_id(id.clone()).is_some() }); @@ -129,26 +132,28 @@ impl FuzzerManager { continue; } }; - todo!() - // let (call_id, name, arguments) = match &panicking_inner_call.data { - // EventData::CallStarted { id, closure, args } => { - // (id.clone(), closure.format(heap), args.clone()) - // } - // EventData::NeedsStarted { - // id, - // condition, - // reason, - // } => (id.clone(), "needs".to_string(), vec![*condition, *reason]), - // _ => unreachable!(), - // }; - // Hint { - // kind: HintKind::Fuzz, - // text: format!( - // "then `{name} {}` panics because {reason}.", - // arguments.iter().map(|arg| arg.format(heap)).join(" "), - // ), - // position: id_to_end_of_line(db, call_id).unwrap(), - // } + let (call_id, name, arguments) = match &panicking_inner_call { + InFiberEvent::CallStarted { id, closure, args } => { + (id.clone(), closure.format(&tracer.heap), args.clone()) + } + InFiberEvent::NeedsStarted { + id, + condition, + reason, + } => (id.clone(), "needs".to_string(), vec![*condition, *reason]), + _ => unreachable!(), + }; + Hint { + kind: HintKind::Fuzz, + text: format!( + "then `{name} {}` panics because {reason}.", + arguments + .iter() + .map(|arg| arg.format(&tracer.heap)) + .join(" "), + ), + position: id_to_end_of_line(db, call_id).unwrap(), + } }; hints.push(vec![first_hint, second_hint]); From 1b25bbf4e1c9f1d425f80a03425e2bb98dea92b3 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 17 Oct 2022 18:12:15 +0200 Subject: [PATCH 18/44] Fix some lints --- compiler/src/main.rs | 8 ++++---- compiler/src/vm/heap/object.rs | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/src/main.rs b/compiler/src/main.rs index dbc3a9371..ebf8bbdd1 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -29,9 +29,9 @@ use crate::{ language_server::utils::LspPositionConversion, module::{Module, ModuleKind}, vm::{ - context::{DbUseProvider, RunForever, RunLimitedNumberOfInstructions}, - tracer::{DummyTracer, FullTracer, Tracer}, - Closure, Status, Struct, Vm, + context::{DbUseProvider, RunForever}, + tracer::{FullTracer, Tracer}, + Closure, ExecutionResult, FiberId, Status, Struct, Vm, }, }; use compiler::lir::Lir; @@ -344,7 +344,7 @@ impl StdoutService { if let Some(CompletedOperation::Received { packet }) = vm.completed_operations.remove(&self.current_receive) { - info!("Sent to stdout: {}", packet.value.format(&packet.heap)); + info!("Sent to stdout: {packet:?}"); self.current_receive = vm.receive(self.channel); } } diff --git a/compiler/src/vm/heap/object.rs b/compiler/src/vm/heap/object.rs index 3ea9d8330..bfe8f1d24 100644 --- a/compiler/src/vm/heap/object.rs +++ b/compiler/src/vm/heap/object.rs @@ -138,9 +138,7 @@ impl Closure { captured: vec![], num_args: 0, body: vec![ - Instruction::TraceModuleStarts { - module: module.clone(), - }, + Instruction::TraceModuleStarts { module }, Instruction::CreateClosure { captured: vec![], num_args: 0, From f2c848acf093d50120875b374e09145ab43856fe Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 17 Oct 2022 21:22:44 +0200 Subject: [PATCH 19/44] Remove logging all stack traces --- compiler/src/vm/tracer/stack_trace.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs index 29ecaec5f..75878c98a 100644 --- a/compiler/src/vm/tracer/stack_trace.rs +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -11,7 +11,6 @@ use crate::{ }; use itertools::Itertools; use std::collections::HashMap; -use tracing::debug; // Stack traces are a reduced view of the tracing state that represent the stack // trace at a given moment in time. @@ -160,7 +159,6 @@ impl FullTracer { } let stack_traces = self.stack_traces(); - debug!("Stack traces: {:?}", stack_traces.keys().collect_vec()); panicking_fiber_chain .into_iter() .rev() From 1b51a9435a0ad946e590efeee6aaa1d55d88e507 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 17 Oct 2022 22:06:59 +0200 Subject: [PATCH 20/44] Remove let_else feature flag --- compiler/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/src/main.rs b/compiler/src/main.rs index ebf8bbdd1..740ad1675 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -2,7 +2,6 @@ #![feature(box_patterns)] #![feature(generic_associated_types)] #![feature(let_chains)] -#![feature(let_else)] #![feature(never_type)] #![feature(try_trait_v2)] #![allow(clippy::module_inception)] From 5686ac0b74e17adf2587032bc20fcd589c976b78 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 17 Oct 2022 22:19:29 +0200 Subject: [PATCH 21/44] Fix Clippy lints --- compiler/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/src/main.rs b/compiler/src/main.rs index 740ad1675..e64dc2263 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -1,6 +1,5 @@ #![feature(async_closure)] #![feature(box_patterns)] -#![feature(generic_associated_types)] #![feature(let_chains)] #![feature(never_type)] #![feature(try_trait_v2)] From 11669c153cdf4624fe8bf776fe770de8add55e65 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sat, 29 Oct 2022 20:35:34 +0200 Subject: [PATCH 22/44] Implement some suggestions Co-Authored-By: Jonas Wanke --- compiler/src/fuzzer/mod.rs | 2 +- compiler/src/fuzzer/utils.rs | 10 +--------- compiler/src/vm/tracer/stack_trace.rs | 6 +++--- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/compiler/src/fuzzer/mod.rs b/compiler/src/fuzzer/mod.rs index 75c007204..2ac7b0f95 100644 --- a/compiler/src/fuzzer/mod.rs +++ b/compiler/src/fuzzer/mod.rs @@ -20,7 +20,7 @@ use tracing::{error, info}; pub async fn fuzz(db: &Database, module: Module) { let (fuzzables_heap, fuzzables): (Heap, Vec<(Id, Pointer)>) = { - let mut tracer = FuzzablesFinder::new(); + let mut tracer = FuzzablesFinder::default(); let mut vm = Vm::new(); vm.set_up_for_running_module_closure(Closure::of_module(db, module).unwrap()); vm.run(&mut DbUseProvider { db }, &mut RunForever, &mut tracer); diff --git a/compiler/src/fuzzer/utils.rs b/compiler/src/fuzzer/utils.rs index d30ee4499..03a74c175 100644 --- a/compiler/src/fuzzer/utils.rs +++ b/compiler/src/fuzzer/utils.rs @@ -8,20 +8,12 @@ use crate::{ }; use std::collections::HashMap; +#[derive(Default)] pub struct FuzzablesFinder { pub fuzzables: Vec<(Id, Pointer)>, pub heap: Heap, transferred_objects: HashMap>, } -impl FuzzablesFinder { - pub fn new() -> Self { - Self { - fuzzables: vec![], - heap: Heap::default(), - transferred_objects: HashMap::new(), - } - } -} impl Tracer for FuzzablesFinder { fn fiber_created(&mut self, _fiber: FiberId) {} fn fiber_done(&mut self, _fiber: FiberId) {} diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs index 75878c98a..d5a58be9e 100644 --- a/compiler/src/vm/tracer/stack_trace.rs +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -45,7 +45,7 @@ impl FullTracer { }); } InFiberEvent::ModuleEnded { .. } => { - stack.pop().unwrap(); + assert!(matches!(stack.pop().unwrap(), StackEntry::Module { .. })); } InFiberEvent::CallStarted { id, closure, args } => { stack.push(StackEntry::Call { @@ -55,7 +55,7 @@ impl FullTracer { }); } InFiberEvent::CallEnded { .. } => { - stack.pop().unwrap(); + assert!(matches!(stack.pop().unwrap(), StackEntry::Call { .. })); } InFiberEvent::NeedsStarted { id, @@ -69,7 +69,7 @@ impl FullTracer { }); } InFiberEvent::NeedsEnded => { - stack.pop().unwrap(); + assert!(matches!(stack.pop().unwrap(), StackEntry::Needs { .. })); } _ => {} } From 7ef6394a191448674d661a32a11266ceb6c9e3ab Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sat, 29 Oct 2022 20:36:34 +0200 Subject: [PATCH 23/44] Apply suggestions from code review Co-authored-by: Jonas Wanke --- compiler/src/vm/tracer/stack_trace.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs index d5a58be9e..23128826e 100644 --- a/compiler/src/vm/tracer/stack_trace.rs +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -36,7 +36,7 @@ impl FullTracer { pub fn stack_traces(&self) -> HashMap> { let mut stacks: HashMap> = HashMap::new(); for timed_event in &self.events { - if let Event::InFiber { fiber, event } = &timed_event.event { + let Event::InFiber { fiber, event } = &timed_event.event else { continue; }; let stack = stacks.entry(*fiber).or_default(); match event { InFiberEvent::ModuleStarted { module } => { From 46f01ba05764aaca9be42fa0bb9935a50bb948c3 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sat, 29 Oct 2022 20:36:49 +0200 Subject: [PATCH 24/44] Update compiler/src/vm/fiber.rs Co-authored-by: Jonas Wanke --- compiler/src/vm/fiber.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index 9e47c2173..0d85dc389 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -123,7 +123,7 @@ impl Fiber { assert_eq!( closure.captured.len(), 0, - "closure is not a module closure (it captures stuff)." + "Closure is not a module closure (it captures stuff)." ); assert_eq!( closure.num_args, 0, From 16d9537293d9b476f7debc6d9a3684b95513b4a1 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sat, 29 Oct 2022 20:37:23 +0200 Subject: [PATCH 25/44] Update compiler/src/vm/fiber.rs Co-authored-by: Jonas Wanke --- compiler/src/vm/fiber.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index 0d85dc389..db60c77aa 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -127,7 +127,7 @@ impl Fiber { ); assert_eq!( closure.num_args, 0, - "closure is not a module closure (it has arguments)." + "Closure is not a module closure (it has arguments)." ); let mut heap = Heap::default(); let closure = heap.create_closure(closure); From a1020009ca07f17c80c736d831db12a302db2f6d Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sat, 29 Oct 2022 21:54:53 +0200 Subject: [PATCH 26/44] Restructure tracing Co-Authored-By: Jonas Wanke --- compiler/src/compiler/hir_to_lir.rs | 1 + compiler/src/compiler/lir.rs | 4 +++- compiler/src/vm/fiber.rs | 33 ++++++++++++++++++++++------- compiler/src/vm/heap/mod.rs | 1 + compiler/src/vm/heap/object.rs | 7 +++++- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/compiler/src/compiler/hir_to_lir.rs b/compiler/src/compiler/hir_to_lir.rs index 22e84e9bb..50462be6a 100644 --- a/compiler/src/compiler/hir_to_lir.rs +++ b/compiler/src/compiler/hir_to_lir.rs @@ -153,6 +153,7 @@ impl LoweringContext { is_curly: bool, ) { self.emit(Instruction::CreateClosure { + id: id.clone(), captured, num_args, body: instructions, diff --git a/compiler/src/compiler/lir.rs b/compiler/src/compiler/lir.rs index 10c55773a..85a534e48 100644 --- a/compiler/src/compiler/lir.rs +++ b/compiler/src/compiler/lir.rs @@ -33,6 +33,7 @@ pub enum Instruction { /// /// a -> a, pointer to closure CreateClosure { + id: hir::Id, captured: Vec, num_args: usize, body: Vec, @@ -137,6 +138,7 @@ impl Display for Instruction { write!(f, "createStruct {num_entries}") } Instruction::CreateClosure { + id, captured, num_args, body: instructions, @@ -144,7 +146,7 @@ impl Display for Instruction { } => { write!( f, - "createClosure with {num_args} {} capturing {} {}", + "createClosure {id} with {num_args} {} capturing {} {}", if *num_args == 1 { "argument" } else { diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index 9e47c2173..dff9b23ee 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -99,23 +99,38 @@ impl Fiber { } } pub fn new_for_running_closure(heap: Heap, closure: Pointer, arguments: &[Pointer]) -> Self { - assert!( - !matches!(heap.get(closure).data, Data::Builtin(_)), - "can only use with closures, not builtins" - ); + let Data::Closure(Closure { id, .. }) = &heap.get(closure).data else { + panic!("Can only use with closures."); + }; + let id = id.clone(); let mut fiber = Self::new_with_heap(heap); - + let runner_closure = fiber.heap.create(Data::Closure(Closure { + id: id.clone(), + captured: vec![], + num_args: 0, + body: vec![ + Instruction::TraceCallStarts { + id: id.clone(), + num_args: arguments.len(), + }, + Instruction::Call { + num_args: arguments.len(), + }, + Instruction::TraceCallEnds, + Instruction::Return, + ], + responsible: None, + })); fiber.data_stack.extend(arguments); fiber.data_stack.push(closure); + fiber.data_stack.push(runner_closure); fiber.status = Status::Running; fiber.run_instruction( &mut PanickingUseProvider, &mut DummyInFiberTracer, - Instruction::Call { - num_args: arguments.len(), - }, + Instruction::Call { num_args: 0 }, ); fiber } @@ -324,6 +339,7 @@ impl Fiber { self.data_stack.push(address); } Instruction::CreateClosure { + id, num_args, body, captured, @@ -337,6 +353,7 @@ impl Fiber { self.heap.dup(*address); } let address = self.heap.create_closure(Closure { + id, captured, num_args, body, diff --git a/compiler/src/vm/heap/mod.rs b/compiler/src/vm/heap/mod.rs index 11f81ca48..ab7dfb4e5 100644 --- a/compiler/src/vm/heap/mod.rs +++ b/compiler/src/vm/heap/mod.rs @@ -191,6 +191,7 @@ impl Heap { .collect(), }), Data::Closure(closure) => Data::Closure(Closure { + id: closure.id.clone(), captured: closure .captured .iter() diff --git a/compiler/src/vm/heap/object.rs b/compiler/src/vm/heap/object.rs index bfe8f1d24..ba63243cc 100644 --- a/compiler/src/vm/heap/object.rs +++ b/compiler/src/vm/heap/object.rs @@ -58,6 +58,7 @@ pub struct Struct { #[derive(Clone)] pub struct Closure { + pub id: Id, pub captured: Vec, pub num_args: usize, pub body: Vec, @@ -135,11 +136,15 @@ impl Struct { impl Closure { pub fn of_module_lir(module: Module, lir: Lir) -> Self { Closure { + id: Id::new(module.clone(), vec![]), captured: vec![], num_args: 0, body: vec![ - Instruction::TraceModuleStarts { module }, + Instruction::TraceModuleStarts { + module: module.clone(), + }, Instruction::CreateClosure { + id: Id::new(module.clone(), vec![]), captured: vec![], num_args: 0, body: lir.instructions, From 4544a7248860af691ee46881e1477363f85f7018 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sat, 29 Oct 2022 21:56:34 +0200 Subject: [PATCH 27/44] Fix indentation Co-Authored-By: Jonas Wanke --- compiler/src/vm/tracer/stack_trace.rs | 69 +++++++++++++-------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs index 23128826e..e6895169b 100644 --- a/compiler/src/vm/tracer/stack_trace.rs +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -37,42 +37,41 @@ impl FullTracer { let mut stacks: HashMap> = HashMap::new(); for timed_event in &self.events { let Event::InFiber { fiber, event } = &timed_event.event else { continue; }; - let stack = stacks.entry(*fiber).or_default(); - match event { - InFiberEvent::ModuleStarted { module } => { - stack.push(StackEntry::Module { - module: module.clone(), - }); - } - InFiberEvent::ModuleEnded { .. } => { - assert!(matches!(stack.pop().unwrap(), StackEntry::Module { .. })); - } - InFiberEvent::CallStarted { id, closure, args } => { - stack.push(StackEntry::Call { - id: id.clone(), - closure: *closure, - args: args.clone(), - }); - } - InFiberEvent::CallEnded { .. } => { - assert!(matches!(stack.pop().unwrap(), StackEntry::Call { .. })); - } - InFiberEvent::NeedsStarted { - id, - condition, - reason, - } => { - stack.push(StackEntry::Needs { - id: id.clone(), - condition: *condition, - reason: *reason, - }); - } - InFiberEvent::NeedsEnded => { - assert!(matches!(stack.pop().unwrap(), StackEntry::Needs { .. })); - } - _ => {} + let stack = stacks.entry(*fiber).or_default(); + match event { + InFiberEvent::ModuleStarted { module } => { + stack.push(StackEntry::Module { + module: module.clone(), + }); + } + InFiberEvent::ModuleEnded { .. } => { + assert!(matches!(stack.pop().unwrap(), StackEntry::Module { .. })); + } + InFiberEvent::CallStarted { id, closure, args } => { + stack.push(StackEntry::Call { + id: id.clone(), + closure: *closure, + args: args.clone(), + }); + } + InFiberEvent::CallEnded { .. } => { + assert!(matches!(stack.pop().unwrap(), StackEntry::Call { .. })); + } + InFiberEvent::NeedsStarted { + id, + condition, + reason, + } => { + stack.push(StackEntry::Needs { + id: id.clone(), + condition: *condition, + reason: *reason, + }); + } + InFiberEvent::NeedsEnded => { + assert!(matches!(stack.pop().unwrap(), StackEntry::Needs { .. })); } + _ => {} } } stacks From 919608d811d8baf7890b8851369ee9027c58b881 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sat, 29 Oct 2022 22:06:32 +0200 Subject: [PATCH 28/44] Pad stack trace strings to width Co-Authored-By: Jonas Wanke --- compiler/Cargo.lock | 10 ++++++++++ compiler/Cargo.toml | 1 + compiler/src/vm/tracer/stack_trace.rs | 17 ++++++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/compiler/Cargo.lock b/compiler/Cargo.lock index abaa46669..d7460d32c 100644 --- a/compiler/Cargo.lock +++ b/compiler/Cargo.lock @@ -117,6 +117,7 @@ dependencies = [ "num-bigint", "num-integer", "num-traits", + "pad", "proptest", "rand", "regex", @@ -746,6 +747,15 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "pad" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3" +dependencies = [ + "unicode-width", +] + [[package]] name = "parking_lot" version = "0.11.2" diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index 122144098..328bc851f 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -21,6 +21,7 @@ notify = "4.0.17" num-bigint = { version = "0.4.3", features = ["rand"] } num-integer = { version = "0.1.45", features = ["i128"] } num-traits = { version = "0.2.15", features = ["i128"] } +pad = "0.1.6" proptest = "1.0.0" rand = "0.8.5" regex = "1.5.5" diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs index e6895169b..8ad1f7dc3 100644 --- a/compiler/src/vm/tracer/stack_trace.rs +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -10,6 +10,7 @@ use crate::{ module::Module, }; use itertools::Itertools; +use pad::PadStr; use std::collections::HashMap; // Stack traces are a reduced view of the tracing state that represent the stack @@ -77,7 +78,7 @@ impl FullTracer { stacks } pub fn format_stack_trace(&self, db: &Database, stack: &[StackEntry]) -> String { - let mut lines = vec![]; + let mut caller_locations_and_calls = vec![]; for entry in stack.iter().rev() { let hir_id = match entry { @@ -133,9 +134,19 @@ impl FullTracer { ), StackEntry::Module { module } => format!("module {module}"), }; - lines.push(format!("{caller_location_string:90} {call_string}")); + caller_locations_and_calls.push((caller_location_string, call_string)); } - lines.join("\n") + + let longest_location = caller_locations_and_calls + .iter() + .map(|(location, _)| location.len()) + .max() + .unwrap(); + + caller_locations_and_calls + .into_iter() + .map(|(location, call)| format!("{} {}", location.pad_to_width(longest_location), call)) + .join("\n") } /// When a VM panics, some child fiber might be responsible for that. This /// function returns a formatted stack trace spanning all fibers in the From dfaaa03a3b3a54b7352fae833187fbbcee9e3bfa Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sat, 29 Oct 2022 23:22:52 +0200 Subject: [PATCH 29/44] Make UseProvider non-mut Co-Authored-By: Jonas Wanke --- compiler/src/fuzzer/fuzzer.rs | 2 +- compiler/src/fuzzer/mod.rs | 2 +- compiler/src/language_server/hints/constant_evaluator.rs | 2 +- compiler/src/main.rs | 4 ++-- compiler/src/vm/context.rs | 6 +++--- compiler/src/vm/fiber.rs | 4 ++-- compiler/src/vm/mod.rs | 4 ++-- compiler/src/vm/use_module.rs | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/src/fuzzer/fuzzer.rs b/compiler/src/fuzzer/fuzzer.rs index e3ec39614..2e2acec41 100644 --- a/compiler/src/fuzzer/fuzzer.rs +++ b/compiler/src/fuzzer/fuzzer.rs @@ -96,7 +96,7 @@ impl Fuzzer { fn map_status( &self, status: Status, - use_provider: &mut U, + use_provider: &U, execution_controller: &mut E, ) -> Status { match status { diff --git a/compiler/src/fuzzer/mod.rs b/compiler/src/fuzzer/mod.rs index 2ac7b0f95..c20bb366f 100644 --- a/compiler/src/fuzzer/mod.rs +++ b/compiler/src/fuzzer/mod.rs @@ -23,7 +23,7 @@ pub async fn fuzz(db: &Database, module: Module) { let mut tracer = FuzzablesFinder::default(); let mut vm = Vm::new(); vm.set_up_for_running_module_closure(Closure::of_module(db, module).unwrap()); - vm.run(&mut DbUseProvider { db }, &mut RunForever, &mut tracer); + vm.run(&DbUseProvider { db }, &mut RunForever, &mut tracer); (tracer.heap, tracer.fuzzables) }; diff --git a/compiler/src/language_server/hints/constant_evaluator.rs b/compiler/src/language_server/hints/constant_evaluator.rs index 0043c8f65..1448a0000 100644 --- a/compiler/src/language_server/hints/constant_evaluator.rs +++ b/compiler/src/language_server/hints/constant_evaluator.rs @@ -57,7 +57,7 @@ impl ConstantEvaluator { if let Some((module, evaluator)) = running_evaluators.choose_mut(&mut thread_rng()) { evaluator.vm.run( - &mut DbUseProvider { db }, + &DbUseProvider { db }, &mut RunLimitedNumberOfInstructions::new(500), &mut evaluator.tracer, ); diff --git a/compiler/src/main.rs b/compiler/src/main.rs index a7f418412..6be9adf01 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -214,7 +214,7 @@ fn run(options: CandyRunOptions) { let mut vm = Vm::new(); vm.set_up_for_running_module_closure(module_closure); - vm.run(&mut DbUseProvider { db: &db }, &mut RunForever, &mut tracer); + vm.run(&DbUseProvider { db: &db }, &mut RunForever, &mut tracer); if let Status::WaitingForOperations = vm.status() { error!("The module waits on channel operations. Perhaps, the code tried to read from a channel without sending a packet into it."); // TODO: Show stack traces of all fibers? @@ -284,7 +284,7 @@ fn run(options: CandyRunOptions) { match vm.status() { Status::CanRun => { debug!("VM still running."); - vm.run(&mut DbUseProvider { db: &db }, &mut RunForever, &mut tracer); + vm.run(&DbUseProvider { db: &db }, &mut RunForever, &mut tracer); } Status::WaitingForOperations => { todo!("VM can't proceed until some operations complete."); diff --git a/compiler/src/vm/context.rs b/compiler/src/vm/context.rs index 2720d150e..971b6c6ec 100644 --- a/compiler/src/vm/context.rs +++ b/compiler/src/vm/context.rs @@ -10,7 +10,7 @@ use crate::{ // of the VM. pub trait UseProvider { - fn use_module(&mut self, module: Module) -> Result; + fn use_module(&self, module: Module) -> Result; } pub enum UseResult { Asset(Vec), @@ -19,7 +19,7 @@ pub enum UseResult { pub struct PanickingUseProvider; impl UseProvider for PanickingUseProvider { - fn use_module(&mut self, _: Module) -> Result { + fn use_module(&self, _: Module) -> Result { panic!() } } @@ -28,7 +28,7 @@ pub struct DbUseProvider<'a> { pub db: &'a Database, } impl<'a> UseProvider for DbUseProvider<'a> { - fn use_module(&mut self, module: Module) -> Result { + fn use_module(&self, module: Module) -> Result { match module.kind { ModuleKind::Asset => match self.db.get_module_content(module.clone()) { Some(bytes) => Ok(UseResult::Asset((*bytes).clone())), diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index c8d274d3d..198337716 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -245,7 +245,7 @@ impl Fiber { pub fn run( &mut self, - use_provider: &mut dyn UseProvider, + use_provider: &dyn UseProvider, execution_controller: &mut dyn ExecutionController, tracer: &mut dyn InFiberTracer, ) { @@ -306,7 +306,7 @@ impl Fiber { } pub fn run_instruction( &mut self, - use_provider: &mut dyn UseProvider, + use_provider: &dyn UseProvider, tracer: &mut dyn InFiberTracer, instruction: Instruction, ) { diff --git a/compiler/src/vm/mod.rs b/compiler/src/vm/mod.rs index e9382b910..9904a0862 100644 --- a/compiler/src/vm/mod.rs +++ b/compiler/src/vm/mod.rs @@ -248,7 +248,7 @@ impl Vm { pub fn run( &mut self, - use_provider: &mut U, + use_provider: &U, execution_controller: &mut E, tracer: &mut dyn Tracer, ) { @@ -265,7 +265,7 @@ impl Vm { } fn run_raw( &mut self, - use_provider: &mut U, + use_provider: &U, execution_controller: &mut E, tracer: &mut dyn Tracer, ) { diff --git a/compiler/src/vm/use_module.rs b/compiler/src/vm/use_module.rs index 5dc670ef5..565900eed 100644 --- a/compiler/src/vm/use_module.rs +++ b/compiler/src/vm/use_module.rs @@ -13,7 +13,7 @@ use itertools::Itertools; impl Fiber { pub fn use_module( &mut self, - use_provider: &mut dyn UseProvider, + use_provider: &dyn UseProvider, current_module: Module, relative_path: Pointer, ) -> Result<(), String> { From 3295ce87268caf10d34c5817471559f2ead33716 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sat, 29 Oct 2022 23:23:01 +0200 Subject: [PATCH 30/44] Add assert in complete_try Co-Authored-By: Jonas Wanke --- compiler/src/vm/fiber.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index 198337716..366173ae9 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -218,6 +218,7 @@ impl Fiber { } } pub fn complete_try(&mut self, result: ExecutionResult) { + assert!(matches!(self.status, Status::InTry { .. })); let result = match result { ExecutionResult::Finished(Packet { heap, From 9e61013d5d50358475b44dd419385af007fe1b0f Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sun, 30 Oct 2022 12:55:50 +0100 Subject: [PATCH 31/44] Restructure tracing (again) --- compiler/src/fuzzer/fuzzer.rs | 6 +- compiler/src/fuzzer/mod.rs | 3 +- compiler/src/fuzzer/utils.rs | 48 +-- .../hints/constant_evaluator.rs | 17 +- compiler/src/language_server/hints/fuzzer.rs | 12 +- compiler/src/main.rs | 25 +- compiler/src/vm/builtin_functions.rs | 6 +- compiler/src/vm/fiber.rs | 24 +- compiler/src/vm/mod.rs | 16 +- compiler/src/vm/tracer/dummy.rs | 7 + compiler/src/vm/tracer/full.rs | 284 ++++++++++++++ compiler/src/vm/tracer/mod.rs | 351 ++++++------------ compiler/src/vm/tracer/stack_trace.rs | 22 +- compiler/src/vm/use_module.rs | 6 +- 14 files changed, 490 insertions(+), 337 deletions(-) create mode 100644 compiler/src/vm/tracer/dummy.rs create mode 100644 compiler/src/vm/tracer/full.rs diff --git a/compiler/src/fuzzer/fuzzer.rs b/compiler/src/fuzzer/fuzzer.rs index 2e2acec41..7391aeca9 100644 --- a/compiler/src/fuzzer/fuzzer.rs +++ b/compiler/src/fuzzer/fuzzer.rs @@ -4,7 +4,7 @@ use crate::{ vm::{ self, context::{ExecutionController, UseProvider}, - tracer::FullTracer, + tracer::{full::FullTracer, Tracer}, Closure, Heap, Packet, Pointer, Vm, }, }; @@ -57,7 +57,7 @@ impl Status { Status::StillFuzzing { vm, arguments, - tracer: FullTracer::new(), + tracer: FullTracer::default(), } } } @@ -102,7 +102,7 @@ impl Fuzzer { match status { Status::StillFuzzing { mut vm, arguments, mut tracer } => match vm.status() { vm::Status::CanRun => { - vm.run(use_provider, execution_controller, &mut tracer); + vm.run(use_provider, execution_controller, &mut tracer.for_vm()); Status::StillFuzzing { vm, arguments, tracer } } vm::Status::WaitingForOperations => panic!("Fuzzing should not have to wait on channel operations because arguments were not channels."), diff --git a/compiler/src/fuzzer/mod.rs b/compiler/src/fuzzer/mod.rs index c20bb366f..06affdfe0 100644 --- a/compiler/src/fuzzer/mod.rs +++ b/compiler/src/fuzzer/mod.rs @@ -12,6 +12,7 @@ use crate::{ module::Module, vm::{ context::{DbUseProvider, RunForever, RunLimitedNumberOfInstructions}, + tracer::Tracer, Closure, Heap, Pointer, Vm, }, }; @@ -23,7 +24,7 @@ pub async fn fuzz(db: &Database, module: Module) { let mut tracer = FuzzablesFinder::default(); let mut vm = Vm::new(); vm.set_up_for_running_module_closure(Closure::of_module(db, module).unwrap()); - vm.run(&DbUseProvider { db }, &mut RunForever, &mut tracer); + vm.run(&DbUseProvider { db }, &mut RunForever, &mut tracer.for_vm()); (tracer.heap, tracer.fuzzables) }; diff --git a/compiler/src/fuzzer/utils.rs b/compiler/src/fuzzer/utils.rs index 03a74c175..0e4bfefdd 100644 --- a/compiler/src/fuzzer/utils.rs +++ b/compiler/src/fuzzer/utils.rs @@ -1,9 +1,8 @@ use crate::{ compiler::hir::Id, - module::Module, vm::{ - tracer::{InFiberTracer, Tracer}, - ChannelId, FiberId, Heap, Pointer, + tracer::{FiberEvent, Tracer, VmEvent}, + FiberId, Heap, Pointer, }, }; use std::collections::HashMap; @@ -15,50 +14,19 @@ pub struct FuzzablesFinder { transferred_objects: HashMap>, } impl Tracer for FuzzablesFinder { - fn fiber_created(&mut self, _fiber: FiberId) {} - fn fiber_done(&mut self, _fiber: FiberId) {} - fn fiber_panicked(&mut self, _fiber: FiberId, _panicked_child: Option) {} - fn fiber_canceled(&mut self, _fiber: FiberId) {} - fn fiber_execution_started(&mut self, _fiber: FiberId) {} - fn fiber_execution_ended(&mut self, _fiber: FiberId) {} - fn channel_created(&mut self, _channel: ChannelId) {} - fn sent_to_channel(&mut self, _value: Pointer, _from: FiberId, _to: ChannelId) {} - fn received_from_channel(&mut self, _value: Pointer, _from: ChannelId, _to: FiberId) {} + fn add(&mut self, event: VmEvent) { + let VmEvent::InFiber { fiber, event } = event else { return; }; + let FiberEvent::FoundFuzzableClosure { id, closure, heap } = event else { return; }; - fn in_fiber_tracer<'a>(&'a mut self, fiber: FiberId) -> Box + 'a> - where - Self: 'a, - { - Box::new(InFiberFuzzablesFinder { - tracer: self, - fiber, - }) - } -} -pub struct InFiberFuzzablesFinder<'a> { - tracer: &'a mut FuzzablesFinder, - fiber: FiberId, -} -impl<'a> InFiberTracer<'a> for InFiberFuzzablesFinder<'a> { - fn module_started(&mut self, _module: Module) {} - fn module_ended(&mut self, _heap: &Heap, _export_map: Pointer) {} - fn value_evaluated(&mut self, _heap: &Heap, _id: Id, _value: Pointer) {} - fn call_started(&mut self, _heap: &Heap, _id: Id, _closure: Pointer, _args: Vec) {} - fn call_ended(&mut self, _heap: &Heap, _return_value: Pointer) {} - fn needs_started(&mut self, _heap: &Heap, _id: Id, _condition: Pointer, _reason: Pointer) {} - fn needs_ended(&mut self) {} - - fn found_fuzzable_closure(&mut self, heap: &Heap, id: Id, closure: Pointer) { let address_map = self - .tracer .transferred_objects - .entry(self.fiber) + .entry(fiber) .or_insert_with(HashMap::new); let address = heap.clone_single_to_other_heap_with_existing_mapping( - &mut self.tracer.heap, + &mut self.heap, closure, address_map, ); - self.tracer.fuzzables.push((id, address)); + self.fuzzables.push((id, address)); } } diff --git a/compiler/src/language_server/hints/constant_evaluator.rs b/compiler/src/language_server/hints/constant_evaluator.rs index 1448a0000..77e5974d0 100644 --- a/compiler/src/language_server/hints/constant_evaluator.rs +++ b/compiler/src/language_server/hints/constant_evaluator.rs @@ -12,7 +12,11 @@ use crate::{ vm::{ self, context::{DbUseProvider, RunLimitedNumberOfInstructions}, - tracer::{stack_trace::StackEntry, Event, FullTracer, InFiberEvent, TimedEvent}, + tracer::{ + full::{FullTracer, StoredFiberEvent, StoredVmEvent, TimedEvent}, + stack_trace::StackEntry, + Tracer, + }, Closure, FiberId, Heap, Pointer, Vm, }, }; @@ -32,7 +36,7 @@ struct Evaluator { impl ConstantEvaluator { pub fn update_module(&mut self, db: &Database, module: Module) { - let tracer = FullTracer::new(); + let tracer = FullTracer::default(); let mut vm = Vm::new(); vm.set_up_for_running_module_closure(Closure::of_module(db, module.clone()).unwrap()); self.evaluators.insert(module, Evaluator { tracer, vm }); @@ -59,7 +63,7 @@ impl ConstantEvaluator { evaluator.vm.run( &DbUseProvider { db }, &mut RunLimitedNumberOfInstructions::new(500), - &mut evaluator.tracer, + &mut evaluator.tracer.for_vm(), ); Some(module.clone()) } else { @@ -74,8 +78,8 @@ impl ConstantEvaluator { .events .iter() .filter_map(|event| match &event.event { - Event::InFiber { - event: InFiberEvent::FoundFuzzableClosure { id, closure }, + StoredVmEvent::InFiber { + event: StoredFiberEvent::FoundFuzzableClosure { id, closure }, .. } => Some((id.clone(), *closure)), _ => None, @@ -99,7 +103,8 @@ impl ConstantEvaluator { }; for TimedEvent { event, .. } in &evaluator.tracer.events { - let Event::InFiber { event: InFiberEvent::ValueEvaluated { id, value }, .. } = event else { continue; }; + let StoredVmEvent::InFiber { event, .. } = event else { continue; }; + let StoredFiberEvent::ValueEvaluated { id, value } = event else { continue; }; if &id.module != module { continue; diff --git a/compiler/src/language_server/hints/fuzzer.rs b/compiler/src/language_server/hints/fuzzer.rs index 84832b302..6121cb132 100644 --- a/compiler/src/language_server/hints/fuzzer.rs +++ b/compiler/src/language_server/hints/fuzzer.rs @@ -9,7 +9,7 @@ use crate::{ module::Module, vm::{ context::{DbUseProvider, RunLimitedNumberOfInstructions}, - tracer::{Event, InFiberEvent}, + tracer::full::{StoredFiberEvent, StoredVmEvent}, Heap, Pointer, }, }; @@ -111,13 +111,13 @@ impl FuzzerManager { // Find the innermost panicking call that is in the // function. .filter_map(|event| match &event.event { - Event::InFiber { event, .. } => Some(event), + StoredVmEvent::InFiber { event, .. } => Some(event), _ => None, }) .find(|event| { let innermost_panicking_call_id = match &event { - InFiberEvent::CallStarted { id, .. } => id, - InFiberEvent::NeedsStarted { id, .. } => id, + StoredFiberEvent::CallStarted { id, .. } => id, + StoredFiberEvent::NeedsStarted { id, .. } => id, _ => return false, }; id.is_same_module_and_any_parent_of(innermost_panicking_call_id) @@ -133,10 +133,10 @@ impl FuzzerManager { } }; let (call_id, name, arguments) = match &panicking_inner_call { - InFiberEvent::CallStarted { id, closure, args } => { + StoredFiberEvent::CallStarted { id, closure, args } => { (id.clone(), closure.format(&tracer.heap), args.clone()) } - InFiberEvent::NeedsStarted { + StoredFiberEvent::NeedsStarted { id, condition, reason, diff --git a/compiler/src/main.rs b/compiler/src/main.rs index 6be9adf01..83cae7fd8 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -28,7 +28,7 @@ use crate::{ module::{Module, ModuleKind}, vm::{ context::{DbUseProvider, RunForever}, - tracer::{FullTracer, Tracer}, + tracer::{full::FullTracer, Tracer}, Closure, ExecutionResult, FiberId, Status, Struct, Vm, }, }; @@ -210,11 +210,15 @@ fn run(options: CandyRunOptions) { debug!("Running `{path_string}`."); let module_closure = Closure::of_module(&db, module.clone()).unwrap(); - let mut tracer = FullTracer::new(); + let mut tracer = FullTracer::default(); let mut vm = Vm::new(); vm.set_up_for_running_module_closure(module_closure); - vm.run(&DbUseProvider { db: &db }, &mut RunForever, &mut tracer); + vm.run( + &DbUseProvider { db: &db }, + &mut RunForever, + &mut tracer.for_vm(), + ); if let Status::WaitingForOperations = vm.status() { error!("The module waits on channel operations. Perhaps, the code tried to read from a channel without sending a packet into it."); // TODO: Show stack traces of all fibers? @@ -273,18 +277,22 @@ fn run(options: CandyRunOptions) { let stdout_port = heap.create_send_port(stdout.channel); heap.create_struct(HashMap::from([(stdout_symbol, stdout_port)])) }; - tracer.in_fiber_tracer(FiberId::root()).call_started( - &heap, + tracer.for_vm().for_fiber(FiberId::root()).call_started( Id::new(module, vec!["main".to_string()]), main, vec![environment], + &heap, ); vm.set_up_for_running_closure(heap, main, &[environment]); loop { match vm.status() { Status::CanRun => { debug!("VM still running."); - vm.run(&DbUseProvider { db: &db }, &mut RunForever, &mut tracer); + vm.run( + &DbUseProvider { db: &db }, + &mut RunForever, + &mut tracer.for_vm(), + ); } Status::WaitingForOperations => { todo!("VM can't proceed until some operations complete."); @@ -299,8 +307,9 @@ fn run(options: CandyRunOptions) { match vm.tear_down() { ExecutionResult::Finished(return_value) => { tracer - .in_fiber_tracer(FiberId::root()) - .call_ended(&return_value.heap, return_value.address); + .for_vm() + .for_fiber(FiberId::root()) + .call_ended(return_value.address, &return_value.heap); debug!("The main function returned: {return_value:?}"); } ExecutionResult::Panicked { diff --git a/compiler/src/vm/builtin_functions.rs b/compiler/src/vm/builtin_functions.rs index 1a3b3a857..494a7dfe3 100644 --- a/compiler/src/vm/builtin_functions.rs +++ b/compiler/src/vm/builtin_functions.rs @@ -4,8 +4,8 @@ use super::{ fiber::{Fiber, Status}, heap::{Closure, Data, Int, Pointer, ReceivePort, SendPort, Struct, Symbol, Text}, ids::ChannelId, - tracer::DummyInFiberTracer, - Heap, + tracer::{dummy::DummyTracer, Tracer}, + FiberId, Heap, }; use crate::{builtin_functions::BuiltinFunction, compiler::lir::Instruction}; use itertools::Itertools; @@ -68,7 +68,7 @@ impl Fiber { self.data_stack.push(closure); self.run_instruction( &mut PanickingUseProvider, - &mut DummyInFiberTracer, + &mut DummyTracer.for_vm().for_fiber(FiberId::root()), Instruction::Call { num_args: 0 }, ); } diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index 366173ae9..8e925c748 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -1,14 +1,14 @@ use super::{ channel::{Capacity, Packet}, - context::{ExecutionController, UseProvider}, + context::{ExecutionController, PanickingUseProvider, UseProvider}, heap::{Builtin, Closure, Data, Heap, Pointer}, ids::ChannelId, - tracer::InFiberTracer, + tracer::{dummy::DummyTracer, FiberTracer, Tracer}, + FiberId, }; use crate::{ compiler::{hir::Id, lir::Instruction}, module::Module, - vm::{context::PanickingUseProvider, tracer::DummyInFiberTracer}, }; use itertools::Itertools; use std::collections::HashMap; @@ -129,7 +129,7 @@ impl Fiber { fiber.status = Status::Running; fiber.run_instruction( &mut PanickingUseProvider, - &mut DummyInFiberTracer, + &mut DummyTracer.for_vm().for_fiber(FiberId::root()), Instruction::Call { num_args: 0 }, ); fiber @@ -248,7 +248,7 @@ impl Fiber { &mut self, use_provider: &dyn UseProvider, execution_controller: &mut dyn ExecutionController, - tracer: &mut dyn InFiberTracer, + tracer: &mut FiberTracer, ) { assert!( matches!(self.status, Status::Running), @@ -308,7 +308,7 @@ impl Fiber { pub fn run_instruction( &mut self, use_provider: &dyn UseProvider, - tracer: &mut dyn InFiberTracer, + tracer: &mut FiberTracer, instruction: Instruction, ) { match instruction { @@ -491,12 +491,12 @@ impl Fiber { panic!("Instruction RegisterFuzzableClosure executed, but stack top is not a closure."); } self.heap.dup(closure); - tracer.found_fuzzable_closure(&self.heap, id, closure); + tracer.found_fuzzable_closure(id, closure, &self.heap); } Instruction::TraceValueEvaluated(id) => { let value = *self.data_stack.last().unwrap(); self.heap.dup(value); - tracer.value_evaluated(&self.heap, id, value); + tracer.value_evaluated(id, value, &self.heap); } Instruction::TraceCallStarts { id, num_args } => { let closure = *self.data_stack.last().unwrap(); @@ -511,19 +511,19 @@ impl Fiber { } args.reverse(); - tracer.call_started(&self.heap, id, closure, args); + tracer.call_started(id, closure, args, &self.heap); } Instruction::TraceCallEnds => { let return_value = *self.data_stack.last().unwrap(); self.heap.dup(return_value); - tracer.call_ended(&self.heap, return_value); + tracer.call_ended(return_value, &self.heap); } Instruction::TraceNeedsStarts { id } => { let condition = self.data_stack[self.data_stack.len() - 2]; let reason = self.data_stack[self.data_stack.len() - 1]; self.heap.dup(condition); self.heap.dup(reason); - tracer.needs_started(&self.heap, id, condition, reason); + tracer.needs_started(id, condition, reason, &self.heap); } Instruction::TraceNeedsEnds => { let nothing = *self.data_stack.last().unwrap(); @@ -549,7 +549,7 @@ impl Fiber { self.import_stack.pop().unwrap(); let export_map = *self.data_stack.last().unwrap(); self.heap.dup(export_map); - tracer.module_ended(&self.heap, export_map); + tracer.module_ended(export_map, &self.heap); } Instruction::Error { id, errors } => { self.panic(format!( diff --git a/compiler/src/vm/mod.rs b/compiler/src/vm/mod.rs index 9904a0862..0b4796ba6 100644 --- a/compiler/src/vm/mod.rs +++ b/compiler/src/vm/mod.rs @@ -21,7 +21,7 @@ use self::{ }, heap::SendPort, ids::{CountableId, IdGenerator}, - tracer::Tracer, + tracer::VmTracer, }; use crate::compiler::hir::Id; use itertools::Itertools; @@ -224,7 +224,7 @@ impl Vm { #[allow(dead_code)] pub fn send( &mut self, - tracer: &mut dyn Tracer, + tracer: &mut VmTracer, channel: ChannelId, packet: Packet, ) -> OperationId { @@ -250,7 +250,7 @@ impl Vm { &mut self, use_provider: &U, execution_controller: &mut E, - tracer: &mut dyn Tracer, + tracer: &mut VmTracer, ) { while self.can_run() && execution_controller.should_continue_running() { self.run_raw( @@ -267,7 +267,7 @@ impl Vm { &mut self, use_provider: &U, execution_controller: &mut E, - tracer: &mut dyn Tracer, + tracer: &mut VmTracer, ) { assert!( self.can_run(), @@ -295,7 +295,7 @@ impl Vm { fiber.run( use_provider, execution_controller, - &mut *tracer.in_fiber_tracer(fiber_id), + &mut tracer.for_fiber(fiber_id), ); tracer.fiber_execution_ended(fiber_id); @@ -462,7 +462,7 @@ impl Vm { } fn finish_parallel( &mut self, - tracer: &mut dyn Tracer, + tracer: &mut VmTracer, parallel_id: FiberId, cause: Performer, result: Result<(), String>, @@ -499,7 +499,7 @@ impl Vm { }, ); } - fn cancel(&mut self, tracer: &mut dyn Tracer, fiber: FiberId) { + fn cancel(&mut self, tracer: &mut VmTracer, fiber: FiberId) { match self.fibers.remove(&fiber).unwrap() { FiberTree::Single(_) => {} FiberTree::Parallel(Parallel { @@ -521,7 +521,7 @@ impl Vm { fn send_to_channel( &mut self, - tracer: &mut dyn Tracer, + tracer: &mut VmTracer, performer: Performer, channel_id: ChannelId, packet: Packet, diff --git a/compiler/src/vm/tracer/dummy.rs b/compiler/src/vm/tracer/dummy.rs new file mode 100644 index 000000000..e5541695e --- /dev/null +++ b/compiler/src/vm/tracer/dummy.rs @@ -0,0 +1,7 @@ +use super::{Tracer, VmEvent}; + +/// A dummy version of the tracer that remembers nothing. +pub struct DummyTracer; +impl Tracer for DummyTracer { + fn add<'event>(&mut self, _: VmEvent<'event>) {} +} diff --git a/compiler/src/vm/tracer/full.rs b/compiler/src/vm/tracer/full.rs new file mode 100644 index 000000000..89767d7c7 --- /dev/null +++ b/compiler/src/vm/tracer/full.rs @@ -0,0 +1,284 @@ +use itertools::Itertools; + +use crate::{ + compiler::hir::Id, + module::Module, + vm::{ChannelId, FiberId, Heap, Pointer}, +}; +use std::{collections::HashMap, fmt, time::Instant}; + +use super::{FiberEvent, Tracer, VmEvent}; + +/// A full tracer that saves all events that occur with timestamps. +#[derive(Clone, Default)] +pub struct FullTracer { + pub events: Vec, + pub heap: Heap, + transferred_objects: HashMap>, +} +#[derive(Clone)] +pub struct TimedEvent { + pub when: Instant, + pub event: StoredVmEvent, +} + +#[derive(Clone)] +pub enum StoredVmEvent { + FiberCreated { + fiber: FiberId, + }, + FiberDone { + fiber: FiberId, + }, + FiberPanicked { + fiber: FiberId, + panicked_child: Option, + }, + FiberCanceled { + fiber: FiberId, + }, + FiberExecutionStarted { + fiber: FiberId, + }, + FiberExecutionEnded { + fiber: FiberId, + }, + ChannelCreated { + channel: ChannelId, + }, + SentToChannel { + value: Pointer, + from: FiberId, + to: ChannelId, + }, + ReceivedFromChannel { + value: Pointer, + from: ChannelId, + to: FiberId, + }, + InFiber { + fiber: FiberId, + event: StoredFiberEvent, + }, +} +#[derive(Clone)] +pub enum StoredFiberEvent { + ModuleStarted { + module: Module, + }, + ModuleEnded { + export_map: Pointer, + }, + ValueEvaluated { + id: Id, + value: Pointer, + }, + FoundFuzzableClosure { + id: Id, + closure: Pointer, + }, + CallStarted { + id: Id, + closure: Pointer, + args: Vec, + }, + CallEnded { + return_value: Pointer, + }, + NeedsStarted { + id: Id, + condition: Pointer, + reason: Pointer, + }, + NeedsEnded, +} + +impl Tracer for FullTracer { + fn add(&mut self, event: VmEvent) { + let event = TimedEvent { + when: Instant::now(), + event: self.map_vm_event(event), + }; + self.events.push(event); + } +} +impl FullTracer { + fn import_from_heap( + &mut self, + address: Pointer, + heap: &Heap, + fiber: Option, + ) -> Pointer { + if let Some(fiber) = fiber { + let map = self + .transferred_objects + .entry(fiber) + .or_insert_with(HashMap::new); + heap.clone_single_to_other_heap_with_existing_mapping(&mut self.heap, address, map) + } else { + heap.clone_single_to_other_heap(&mut self.heap, address) + } + } + + fn map_vm_event(&mut self, event: VmEvent) -> StoredVmEvent { + match event { + VmEvent::FiberCreated { fiber } => StoredVmEvent::FiberCreated { fiber }, + VmEvent::FiberDone { fiber } => StoredVmEvent::FiberDone { fiber }, + VmEvent::FiberPanicked { + fiber, + panicked_child, + } => StoredVmEvent::FiberPanicked { + fiber, + panicked_child, + }, + VmEvent::FiberCanceled { fiber } => StoredVmEvent::FiberCanceled { fiber }, + VmEvent::FiberExecutionStarted { fiber } => { + StoredVmEvent::FiberExecutionStarted { fiber } + } + VmEvent::FiberExecutionEnded { fiber } => StoredVmEvent::FiberExecutionEnded { fiber }, + VmEvent::ChannelCreated { channel } => StoredVmEvent::ChannelCreated { channel }, + VmEvent::SentToChannel { + value, + from, + to, + heap, + } => { + let value = self.import_from_heap(value, heap, None); + StoredVmEvent::SentToChannel { value, from, to } + } + VmEvent::ReceivedFromChannel { + value, + from, + to, + heap, + } => { + let value = self.import_from_heap(value, heap, None); + StoredVmEvent::ReceivedFromChannel { value, from, to } + } + VmEvent::InFiber { fiber, event } => StoredVmEvent::InFiber { + fiber, + event: self.map_fiber_event(event, fiber), + }, + } + } + fn map_fiber_event(&mut self, event: FiberEvent, fiber: FiberId) -> StoredFiberEvent { + match event { + FiberEvent::ModuleStarted { module } => StoredFiberEvent::ModuleStarted { module }, + FiberEvent::ModuleEnded { export_map, heap } => { + let export_map = self.import_from_heap(export_map, heap, Some(fiber)); + StoredFiberEvent::ModuleEnded { export_map } + } + FiberEvent::ValueEvaluated { id, value, heap } => { + let value = self.import_from_heap(value, heap, Some(fiber)); + StoredFiberEvent::ValueEvaluated { id, value } + } + FiberEvent::FoundFuzzableClosure { id, closure, heap } => { + let closure = self.import_from_heap(closure, heap, Some(fiber)); + StoredFiberEvent::FoundFuzzableClosure { id, closure } + } + FiberEvent::CallStarted { + id, + closure, + args, + heap, + } => { + let closure = self.import_from_heap(closure, heap, Some(fiber)); + let args = args + .into_iter() + .map(|arg| self.import_from_heap(arg, heap, Some(fiber))) + .collect(); + StoredFiberEvent::CallStarted { id, closure, args } + } + FiberEvent::CallEnded { return_value, heap } => { + let return_value = self.import_from_heap(return_value, heap, Some(fiber)); + StoredFiberEvent::CallEnded { return_value } + } + FiberEvent::NeedsStarted { + id, + condition, + reason, + heap, + } => { + let condition = self.import_from_heap(condition, heap, Some(fiber)); + let reason = self.import_from_heap(reason, heap, Some(fiber)); + StoredFiberEvent::NeedsStarted { + id, + condition, + reason, + } + } + FiberEvent::NeedsEnded => StoredFiberEvent::NeedsEnded, + } + } +} + +impl fmt::Debug for FullTracer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let start = self.events.first().map(|event| event.when); + for event in &self.events { + writeln!( + f, + "{:?} us: {}", + event.when.duration_since(start.unwrap()).as_micros(), + match &event.event { + StoredVmEvent::FiberCreated { fiber } => format!("{fiber:?}: created"), + StoredVmEvent::FiberDone { fiber } => format!("{fiber:?}: done"), + StoredVmEvent::FiberPanicked { + fiber, + panicked_child, + } => format!( + "{fiber:?}: panicked{}", + if let Some(child) = panicked_child { + format!(" because child {child:?} panicked") + } else { + "".to_string() + } + ), + StoredVmEvent::FiberCanceled { fiber } => format!("{fiber:?}: canceled"), + StoredVmEvent::FiberExecutionStarted { fiber } => + format!("{fiber:?}: execution started"), + StoredVmEvent::FiberExecutionEnded { fiber } => + format!("{fiber:?}: execution ended"), + StoredVmEvent::ChannelCreated { channel } => format!("{channel:?}: created"), + StoredVmEvent::SentToChannel { value, from, to } => + format!("{from:?} sent {} to {to:?}", value.format(&self.heap)), + StoredVmEvent::ReceivedFromChannel { value, from, to } => + format!("{to:?} received {} from {from:?}", value.format(&self.heap)), + StoredVmEvent::InFiber { fiber, event } => format!( + "{fiber:?}: {}", + match event { + StoredFiberEvent::ModuleStarted { module } => + format!("module {module} started"), + StoredFiberEvent::ModuleEnded { export_map } => format!( + "module ended and exported {}", + export_map.format(&self.heap) + ), + StoredFiberEvent::ValueEvaluated { id, value } => + format!("value {id} is {}", value.format(&self.heap)), + StoredFiberEvent::FoundFuzzableClosure { id, .. } => + format!("found fuzzable closure {id}"), + StoredFiberEvent::CallStarted { id, closure, args } => format!( + "call {id} started: {} {}", + closure.format(&self.heap), + args.iter().map(|arg| arg.format(&self.heap)).join(" ") + ), + StoredFiberEvent::CallEnded { return_value } => + format!("call ended: {}", return_value.format(&self.heap)), + StoredFiberEvent::NeedsStarted { + id, + condition, + reason, + } => format!( + "needs {id} started: needs {} {}", + condition.format(&self.heap), + reason.format(&self.heap) + ), + StoredFiberEvent::NeedsEnded => "needs ended".to_string(), + } + ), + } + )?; + } + Ok(()) + } +} diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index 88f2ecc24..303275bf1 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -1,86 +1,13 @@ +pub mod dummy; +pub mod full; pub mod stack_trace; use super::{heap::Pointer, ChannelId, FiberId, Heap}; use crate::{compiler::hir::Id, module::Module}; -use itertools::Itertools; -use std::{collections::HashMap, fmt, time::Instant}; - -pub trait Tracer { - fn fiber_created(&mut self, fiber: FiberId); - fn fiber_done(&mut self, fiber: FiberId); - fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option); - fn fiber_canceled(&mut self, fiber: FiberId); - fn fiber_execution_started(&mut self, fiber: FiberId); - fn fiber_execution_ended(&mut self, fiber: FiberId); - fn channel_created(&mut self, channel: ChannelId); - fn sent_to_channel(&mut self, value: Pointer, from: FiberId, to: ChannelId); - fn received_from_channel(&mut self, value: Pointer, from: ChannelId, to: FiberId); - - fn in_fiber_tracer<'a>(&'a mut self, fiber: FiberId) -> Box + 'a> - where - Self: 'a; -} - -pub trait InFiberTracer<'a> { - fn module_started(&mut self, module: Module); - fn module_ended(&mut self, heap: &Heap, export_map: Pointer); - fn value_evaluated(&mut self, heap: &Heap, id: Id, value: Pointer); - fn found_fuzzable_closure(&mut self, heap: &Heap, id: Id, closure: Pointer); - fn call_started(&mut self, heap: &Heap, id: Id, closure: Pointer, args: Vec); - fn call_ended(&mut self, heap: &Heap, return_value: Pointer); - fn needs_started(&mut self, heap: &Heap, id: Id, condition: Pointer, reason: Pointer); - fn needs_ended(&mut self); -} - -// A dummy version of the tracer that is used when running known instructions -// without wanting to trace them. - -pub struct DummyTracer; -pub struct DummyInFiberTracer; -impl Tracer for DummyTracer { - fn fiber_created(&mut self, _fiber: FiberId) {} - fn fiber_done(&mut self, _fiber: FiberId) {} - fn fiber_panicked(&mut self, _fiber: FiberId, _panicked_child: Option) {} - fn fiber_canceled(&mut self, _fiber: FiberId) {} - fn fiber_execution_started(&mut self, _fiber: FiberId) {} - fn fiber_execution_ended(&mut self, _fiber: FiberId) {} - fn channel_created(&mut self, _channel: ChannelId) {} - fn sent_to_channel(&mut self, _value: Pointer, _from: FiberId, _to: ChannelId) {} - fn received_from_channel(&mut self, _value: Pointer, _from: ChannelId, _to: FiberId) {} - - fn in_fiber_tracer<'a>(&'a mut self, _fiber: FiberId) -> Box> - where - Self: 'a, - { - Box::new(DummyInFiberTracer) - } -} -impl<'a> InFiberTracer<'a> for DummyInFiberTracer { - fn module_started(&mut self, _module: Module) {} - fn module_ended(&mut self, _heap: &Heap, _export_map: Pointer) {} - fn value_evaluated(&mut self, _heap: &Heap, _id: Id, _value: Pointer) {} - fn found_fuzzable_closure(&mut self, _heap: &Heap, _id: Id, _closure: Pointer) {} - fn call_started(&mut self, _heap: &Heap, _id: Id, _closure: Pointer, _args: Vec) {} - fn call_ended(&mut self, _heap: &Heap, _return_value: Pointer) {} - fn needs_started(&mut self, _heap: &Heap, _id: Id, _condition: Pointer, _reason: Pointer) {} - fn needs_ended(&mut self) {} -} - -// A full tracer that saves all events that occur with timestamps. +/// An event that happened inside a VM. #[derive(Clone)] -pub struct FullTracer { - pub events: Vec, - pub heap: Heap, - transferred_objects: HashMap>, -} -#[derive(Clone)] -pub struct TimedEvent { - pub when: Instant, - pub event: Event, -} -#[derive(Clone)] -pub enum Event { +pub enum VmEvent<'event> { FiberCreated { fiber: FiberId, }, @@ -107,237 +34,185 @@ pub enum Event { value: Pointer, from: FiberId, to: ChannelId, + heap: &'event Heap, }, ReceivedFromChannel { value: Pointer, from: ChannelId, to: FiberId, + heap: &'event Heap, }, InFiber { fiber: FiberId, - event: InFiberEvent, + event: FiberEvent<'event>, }, } + +/// An event that happened inside a fiber. #[derive(Clone)] -pub enum InFiberEvent { +pub enum FiberEvent<'event> { ModuleStarted { module: Module, }, ModuleEnded { export_map: Pointer, + heap: &'event Heap, }, ValueEvaluated { id: Id, value: Pointer, + heap: &'event Heap, }, FoundFuzzableClosure { id: Id, closure: Pointer, + heap: &'event Heap, }, CallStarted { id: Id, closure: Pointer, args: Vec, + heap: &'event Heap, }, CallEnded { return_value: Pointer, + heap: &'event Heap, }, NeedsStarted { id: Id, condition: Pointer, reason: Pointer, + heap: &'event Heap, }, NeedsEnded, } -impl FullTracer { - pub fn new() -> Self { - Self { - events: vec![], - heap: Heap::default(), - transferred_objects: HashMap::new(), +pub trait Tracer { + fn add<'event>(&mut self, event: VmEvent<'event>); + + fn for_vm<'a, 'vm>(&'a mut self) -> VmTracer<'vm> + where + Self: Sized, + 'a: 'vm, + { + VmTracer::<'vm> { tracer: self } + } +} +pub struct VmTracer<'vm> { + tracer: &'vm mut dyn Tracer, +} +pub struct FiberTracer<'vm, 'fiber> { + vm_tracer: &'fiber mut VmTracer<'vm>, + fiber: FiberId, +} + +impl<'vm> VmTracer<'vm> { + pub fn for_fiber<'fiber>(&'fiber mut self, fiber: FiberId) -> FiberTracer<'vm, 'fiber> + where + Self: 'fiber, + { + FiberTracer { + vm_tracer: self, + fiber, } } - fn push(&mut self, data: Event) { - self.events.push(TimedEvent { - when: Instant::now(), - event: data, - }); +} + +impl<'vm> VmTracer<'vm> { + fn add<'event>(&mut self, event: VmEvent<'event>) { + self.tracer.add(event); } - fn import_from_fiber_heap(&mut self, fiber: FiberId, heap: &Heap, value: Pointer) -> Pointer { - let address_map = self - .transferred_objects - .entry(fiber) - .or_insert_with(HashMap::new); - heap.clone_single_to_other_heap_with_existing_mapping(&mut self.heap, value, address_map) +} +impl<'vm, 'fiber> FiberTracer<'vm, 'fiber> { + fn add<'event>(&mut self, event: FiberEvent<'event>) { + self.vm_tracer.add(VmEvent::InFiber { + fiber: self.fiber, + event, + }); } } -impl Tracer for FullTracer { - fn fiber_created(&mut self, fiber: FiberId) { - self.push(Event::FiberCreated { fiber }); + +impl<'vm> VmTracer<'vm> { + pub fn fiber_created(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberCreated { fiber }); } - fn fiber_done(&mut self, fiber: FiberId) { - self.push(Event::FiberDone { fiber }); + pub fn fiber_done(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberDone { fiber }); } - fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option) { - self.push(Event::FiberPanicked { + pub fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option) { + self.add(VmEvent::FiberPanicked { fiber, panicked_child, }); } - fn fiber_canceled(&mut self, fiber: FiberId) { - self.push(Event::FiberCanceled { fiber }); - } - fn fiber_execution_started(&mut self, fiber: FiberId) { - self.push(Event::FiberExecutionStarted { fiber }); - } - fn fiber_execution_ended(&mut self, fiber: FiberId) { - self.push(Event::FiberExecutionEnded { fiber }); - } - fn channel_created(&mut self, channel: ChannelId) { - self.push(Event::ChannelCreated { channel }); + pub fn fiber_canceled(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberCanceled { fiber }); } - fn sent_to_channel(&mut self, value: Pointer, from: FiberId, to: ChannelId) { - self.push(Event::SentToChannel { value, from, to }); + pub fn fiber_execution_started(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberExecutionStarted { fiber }); } - fn received_from_channel(&mut self, value: Pointer, from: ChannelId, to: FiberId) { - self.push(Event::ReceivedFromChannel { value, from, to }); + pub fn fiber_execution_ended(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberExecutionEnded { fiber }); } - - fn in_fiber_tracer<'a>(&'a mut self, fiber: FiberId) -> Box + 'a> - where - Self: 'a, - { - Box::new(FullInFiberTracer { - tracer: self, - fiber, - }) + pub fn channel_created(&mut self, channel: ChannelId) { + self.add(VmEvent::ChannelCreated { channel }); } -} - -pub struct FullInFiberTracer<'a> { - tracer: &'a mut FullTracer, - fiber: FiberId, -} -impl<'a> FullInFiberTracer<'a> { - fn import_from_fiber_heap(&mut self, heap: &Heap, value: Pointer) -> Pointer { - self.tracer.import_from_fiber_heap(self.fiber, heap, value) + pub fn sent_to_channel(&mut self, value: Pointer, from: FiberId, to: ChannelId, heap: &Heap) { + self.add(VmEvent::SentToChannel { + value, + from, + to, + heap, + }); } - fn push(&mut self, event: InFiberEvent) { - self.tracer.push(Event::InFiber { - fiber: self.fiber, - event, + pub fn received_from_channel( + &mut self, + value: Pointer, + from: ChannelId, + to: FiberId, + heap: &Heap, + ) { + self.add(VmEvent::ReceivedFromChannel { + value, + from, + to, + heap, }); } } -impl<'a> InFiberTracer<'a> for FullInFiberTracer<'a> { - fn module_started(&mut self, module: Module) { - self.push(InFiberEvent::ModuleStarted { module }); +impl<'vm, 'fiber> FiberTracer<'vm, 'fiber> { + pub fn module_started(&mut self, module: Module) { + self.add(FiberEvent::ModuleStarted { module }); } - fn module_ended(&mut self, heap: &Heap, export_map: Pointer) { - let export_map = self.import_from_fiber_heap(heap, export_map); - self.push(InFiberEvent::ModuleEnded { export_map }); + pub fn module_ended(&mut self, export_map: Pointer, heap: &Heap) { + self.add(FiberEvent::ModuleEnded { export_map, heap }); } - fn value_evaluated(&mut self, heap: &Heap, id: Id, value: Pointer) { - let value = self.import_from_fiber_heap(heap, value); - self.push(InFiberEvent::ValueEvaluated { id, value }); + pub fn value_evaluated(&mut self, id: Id, value: Pointer, heap: &Heap) { + self.add(FiberEvent::ValueEvaluated { id, value, heap }); } - fn found_fuzzable_closure(&mut self, heap: &Heap, id: Id, closure: Pointer) { - let closure = self.import_from_fiber_heap(heap, closure); - self.push(InFiberEvent::FoundFuzzableClosure { id, closure }); + pub fn found_fuzzable_closure(&mut self, id: Id, closure: Pointer, heap: &Heap) { + self.add(FiberEvent::FoundFuzzableClosure { id, closure, heap }); } - fn call_started(&mut self, heap: &Heap, id: Id, closure: Pointer, args: Vec) { - let closure = self.import_from_fiber_heap(heap, closure); - let args = args - .into_iter() - .map(|arg| self.import_from_fiber_heap(heap, arg)) - .collect(); - self.push(InFiberEvent::CallStarted { id, closure, args }); + pub fn call_started(&mut self, id: Id, closure: Pointer, args: Vec, heap: &Heap) { + self.add(FiberEvent::CallStarted { + id, + closure, + args, + heap, + }); } - fn call_ended(&mut self, heap: &Heap, return_value: Pointer) { - let return_value = self.import_from_fiber_heap(heap, return_value); - self.push(InFiberEvent::CallEnded { return_value }); + pub fn call_ended(&mut self, return_value: Pointer, heap: &Heap) { + self.add(FiberEvent::CallEnded { return_value, heap }); } - fn needs_started(&mut self, heap: &Heap, id: Id, condition: Pointer, reason: Pointer) { - let condition = self.import_from_fiber_heap(heap, condition); - let reason = self.import_from_fiber_heap(heap, reason); - self.push(InFiberEvent::NeedsStarted { + pub fn needs_started(&mut self, id: Id, condition: Pointer, reason: Pointer, heap: &Heap) { + self.add(FiberEvent::NeedsStarted { id, condition, reason, + heap, }); } - fn needs_ended(&mut self) { - self.push(InFiberEvent::NeedsEnded); - } -} - -impl fmt::Debug for FullTracer { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let start = self.events.first().map(|event| event.when); - for event in &self.events { - writeln!( - f, - "{:?} us: {}", - event.when.duration_since(start.unwrap()).as_micros(), - match &event.event { - Event::FiberCreated { fiber } => format!("{fiber:?}: created"), - Event::FiberDone { fiber } => format!("{fiber:?}: done"), - Event::FiberPanicked { - fiber, - panicked_child, - } => format!( - "{fiber:?}: panicked{}", - if let Some(child) = panicked_child { - format!(" because child {child:?} panicked") - } else { - "".to_string() - } - ), - Event::FiberCanceled { fiber } => format!("{fiber:?}: canceled"), - Event::FiberExecutionStarted { fiber } => - format!("{fiber:?}: execution started"), - Event::FiberExecutionEnded { fiber } => format!("{fiber:?}: execution ended"), - Event::ChannelCreated { channel } => format!("{channel:?}: created"), - Event::SentToChannel { value, from, to } => - format!("{from:?} sent {} to {to:?}", value.format(&self.heap)), - Event::ReceivedFromChannel { value, from, to } => - format!("{to:?} received {} from {from:?}", value.format(&self.heap)), - Event::InFiber { fiber, event } => format!( - "{fiber:?}: {}", - match event { - InFiberEvent::ModuleStarted { module } => - format!("module {module} started"), - InFiberEvent::ModuleEnded { export_map } => format!( - "module ended and exported {}", - export_map.format(&self.heap) - ), - InFiberEvent::ValueEvaluated { id, value } => - format!("value {id} is {}", value.format(&self.heap)), - InFiberEvent::FoundFuzzableClosure { id, .. } => - format!("found fuzzable closure {id}"), - InFiberEvent::CallStarted { id, closure, args } => format!( - "call {id} started: {} {}", - closure.format(&self.heap), - args.iter().map(|arg| arg.format(&self.heap)).join(" ") - ), - InFiberEvent::CallEnded { return_value } => - format!("call ended: {}", return_value.format(&self.heap)), - InFiberEvent::NeedsStarted { - id, - condition, - reason, - } => format!( - "needs {id} started: needs {} {}", - condition.format(&self.heap), - reason.format(&self.heap) - ), - InFiberEvent::NeedsEnded => "needs ended".to_string(), - } - ), - } - )?; - } - Ok(()) + pub fn needs_ended(&mut self) { + self.add(FiberEvent::NeedsEnded); } } diff --git a/compiler/src/vm/tracer/stack_trace.rs b/compiler/src/vm/tracer/stack_trace.rs index 8ad1f7dc3..ae001b017 100644 --- a/compiler/src/vm/tracer/stack_trace.rs +++ b/compiler/src/vm/tracer/stack_trace.rs @@ -1,4 +1,8 @@ -use super::{super::heap::Pointer, Event, FiberId, FullTracer, InFiberEvent}; +use super::{ + super::heap::Pointer, + full::{FullTracer, StoredFiberEvent, StoredVmEvent}, + FiberId, +}; use crate::{ compiler::{ ast_to_hir::AstToHir, @@ -37,28 +41,28 @@ impl FullTracer { pub fn stack_traces(&self) -> HashMap> { let mut stacks: HashMap> = HashMap::new(); for timed_event in &self.events { - let Event::InFiber { fiber, event } = &timed_event.event else { continue; }; + let StoredVmEvent::InFiber { fiber, event } = &timed_event.event else { continue; }; let stack = stacks.entry(*fiber).or_default(); match event { - InFiberEvent::ModuleStarted { module } => { + StoredFiberEvent::ModuleStarted { module } => { stack.push(StackEntry::Module { module: module.clone(), }); } - InFiberEvent::ModuleEnded { .. } => { + StoredFiberEvent::ModuleEnded { .. } => { assert!(matches!(stack.pop().unwrap(), StackEntry::Module { .. })); } - InFiberEvent::CallStarted { id, closure, args } => { + StoredFiberEvent::CallStarted { id, closure, args } => { stack.push(StackEntry::Call { id: id.clone(), closure: *closure, args: args.clone(), }); } - InFiberEvent::CallEnded { .. } => { + StoredFiberEvent::CallEnded { .. } => { assert!(matches!(stack.pop().unwrap(), StackEntry::Call { .. })); } - InFiberEvent::NeedsStarted { + StoredFiberEvent::NeedsStarted { id, condition, reason, @@ -69,7 +73,7 @@ impl FullTracer { reason: *reason, }); } - InFiberEvent::NeedsEnded => { + StoredFiberEvent::NeedsEnded => { assert!(matches!(stack.pop().unwrap(), StackEntry::Needs { .. })); } _ => {} @@ -154,7 +158,7 @@ impl FullTracer { pub fn format_panic_stack_trace_to_root_fiber(&self, db: &Database) -> String { let mut panicking_fiber_chain = vec![FiberId::root()]; for timed_event in self.events.iter().rev() { - if let Event::FiberPanicked { + if let StoredVmEvent::FiberPanicked { fiber, panicked_child, } = timed_event.event diff --git a/compiler/src/vm/use_module.rs b/compiler/src/vm/use_module.rs index 565900eed..8343ead59 100644 --- a/compiler/src/vm/use_module.rs +++ b/compiler/src/vm/use_module.rs @@ -1,8 +1,8 @@ use super::{ context::{PanickingUseProvider, UseProvider, UseResult}, heap::{Closure, Heap, Pointer, Text}, - tracer::DummyInFiberTracer, - Fiber, + tracer::{dummy::DummyTracer, Tracer}, + Fiber, FiberId, }; use crate::{ compiler::lir::Instruction, @@ -35,7 +35,7 @@ impl Fiber { self.data_stack.push(address); self.run_instruction( &mut PanickingUseProvider, - &mut DummyInFiberTracer, + &mut DummyTracer.for_vm().for_fiber(FiberId::root()), Instruction::Call { num_args: 0 }, ); } From 36bce9c448de2040a31bf35502fc320a04d3a57d Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sun, 30 Oct 2022 12:59:52 +0100 Subject: [PATCH 32/44] Improve tracing of finishing fibers --- compiler/src/vm/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/src/vm/mod.rs b/compiler/src/vm/mod.rs index 0b4796ba6..902d242a7 100644 --- a/compiler/src/vm/mod.rs +++ b/compiler/src/vm/mod.rs @@ -374,7 +374,14 @@ impl Vm { false } - fiber::Status::Done | fiber::Status::Panicked { .. } => true, + fiber::Status::Done => { + tracer.fiber_done(fiber_id); + true + } + fiber::Status::Panicked { .. } => { + tracer.fiber_panicked(fiber_id, None); + true + } }; if is_finished && fiber_id != FiberId::root() { From 6699e3b3dd07f664fadc610cef762c0a0f1d6882 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sun, 30 Oct 2022 13:00:02 +0100 Subject: [PATCH 33/44] Remove unused events --- compiler/src/vm/tracer/full.rs | 32 -------------------------------- compiler/src/vm/tracer/mod.rs | 34 ---------------------------------- 2 files changed, 66 deletions(-) diff --git a/compiler/src/vm/tracer/full.rs b/compiler/src/vm/tracer/full.rs index 89767d7c7..d2797958f 100644 --- a/compiler/src/vm/tracer/full.rs +++ b/compiler/src/vm/tracer/full.rs @@ -46,16 +46,6 @@ pub enum StoredVmEvent { ChannelCreated { channel: ChannelId, }, - SentToChannel { - value: Pointer, - from: FiberId, - to: ChannelId, - }, - ReceivedFromChannel { - value: Pointer, - from: ChannelId, - to: FiberId, - }, InFiber { fiber: FiberId, event: StoredFiberEvent, @@ -137,24 +127,6 @@ impl FullTracer { } VmEvent::FiberExecutionEnded { fiber } => StoredVmEvent::FiberExecutionEnded { fiber }, VmEvent::ChannelCreated { channel } => StoredVmEvent::ChannelCreated { channel }, - VmEvent::SentToChannel { - value, - from, - to, - heap, - } => { - let value = self.import_from_heap(value, heap, None); - StoredVmEvent::SentToChannel { value, from, to } - } - VmEvent::ReceivedFromChannel { - value, - from, - to, - heap, - } => { - let value = self.import_from_heap(value, heap, None); - StoredVmEvent::ReceivedFromChannel { value, from, to } - } VmEvent::InFiber { fiber, event } => StoredVmEvent::InFiber { fiber, event: self.map_fiber_event(event, fiber), @@ -240,10 +212,6 @@ impl fmt::Debug for FullTracer { StoredVmEvent::FiberExecutionEnded { fiber } => format!("{fiber:?}: execution ended"), StoredVmEvent::ChannelCreated { channel } => format!("{channel:?}: created"), - StoredVmEvent::SentToChannel { value, from, to } => - format!("{from:?} sent {} to {to:?}", value.format(&self.heap)), - StoredVmEvent::ReceivedFromChannel { value, from, to } => - format!("{to:?} received {} from {from:?}", value.format(&self.heap)), StoredVmEvent::InFiber { fiber, event } => format!( "{fiber:?}: {}", match event { diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index 303275bf1..0e55c41ca 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -30,18 +30,6 @@ pub enum VmEvent<'event> { ChannelCreated { channel: ChannelId, }, - SentToChannel { - value: Pointer, - from: FiberId, - to: ChannelId, - heap: &'event Heap, - }, - ReceivedFromChannel { - value: Pointer, - from: ChannelId, - to: FiberId, - heap: &'event Heap, - }, InFiber { fiber: FiberId, event: FiberEvent<'event>, @@ -157,28 +145,6 @@ impl<'vm> VmTracer<'vm> { pub fn channel_created(&mut self, channel: ChannelId) { self.add(VmEvent::ChannelCreated { channel }); } - pub fn sent_to_channel(&mut self, value: Pointer, from: FiberId, to: ChannelId, heap: &Heap) { - self.add(VmEvent::SentToChannel { - value, - from, - to, - heap, - }); - } - pub fn received_from_channel( - &mut self, - value: Pointer, - from: ChannelId, - to: FiberId, - heap: &Heap, - ) { - self.add(VmEvent::ReceivedFromChannel { - value, - from, - to, - heap, - }); - } } impl<'vm, 'fiber> FiberTracer<'vm, 'fiber> { pub fn module_started(&mut self, module: Module) { From ce36027de109608d379d2f4a6c8edfc865fff469 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sun, 30 Oct 2022 13:12:54 +0100 Subject: [PATCH 34/44] Fix clippy lints --- compiler/src/vm/builtin_functions.rs | 2 +- compiler/src/vm/fiber.rs | 4 ++-- compiler/src/vm/heap/object.rs | 2 +- compiler/src/vm/tracer/dummy.rs | 2 +- compiler/src/vm/tracer/mod.rs | 6 +++--- compiler/src/vm/use_module.rs | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/src/vm/builtin_functions.rs b/compiler/src/vm/builtin_functions.rs index 494a7dfe3..be2a72d8a 100644 --- a/compiler/src/vm/builtin_functions.rs +++ b/compiler/src/vm/builtin_functions.rs @@ -67,7 +67,7 @@ impl Fiber { Ok(DivergeControlFlow { closure }) => { self.data_stack.push(closure); self.run_instruction( - &mut PanickingUseProvider, + &PanickingUseProvider, &mut DummyTracer.for_vm().for_fiber(FiberId::root()), Instruction::Call { num_args: 0 }, ); diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index 8e925c748..823a517d1 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -111,7 +111,7 @@ impl Fiber { num_args: 0, body: vec![ Instruction::TraceCallStarts { - id: id.clone(), + id, num_args: arguments.len(), }, Instruction::Call { @@ -128,7 +128,7 @@ impl Fiber { fiber.status = Status::Running; fiber.run_instruction( - &mut PanickingUseProvider, + &PanickingUseProvider, &mut DummyTracer.for_vm().for_fiber(FiberId::root()), Instruction::Call { num_args: 0 }, ); diff --git a/compiler/src/vm/heap/object.rs b/compiler/src/vm/heap/object.rs index ba63243cc..eca493e5f 100644 --- a/compiler/src/vm/heap/object.rs +++ b/compiler/src/vm/heap/object.rs @@ -144,7 +144,7 @@ impl Closure { module: module.clone(), }, Instruction::CreateClosure { - id: Id::new(module.clone(), vec![]), + id: Id::new(module, vec![]), captured: vec![], num_args: 0, body: lir.instructions, diff --git a/compiler/src/vm/tracer/dummy.rs b/compiler/src/vm/tracer/dummy.rs index e5541695e..dbd4f05b3 100644 --- a/compiler/src/vm/tracer/dummy.rs +++ b/compiler/src/vm/tracer/dummy.rs @@ -3,5 +3,5 @@ use super::{Tracer, VmEvent}; /// A dummy version of the tracer that remembers nothing. pub struct DummyTracer; impl Tracer for DummyTracer { - fn add<'event>(&mut self, _: VmEvent<'event>) {} + fn add(&mut self, _: VmEvent) {} } diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index 0e55c41ca..a0d5bb029 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -76,7 +76,7 @@ pub enum FiberEvent<'event> { } pub trait Tracer { - fn add<'event>(&mut self, event: VmEvent<'event>); + fn add(&mut self, event: VmEvent); fn for_vm<'a, 'vm>(&'a mut self) -> VmTracer<'vm> where @@ -107,12 +107,12 @@ impl<'vm> VmTracer<'vm> { } impl<'vm> VmTracer<'vm> { - fn add<'event>(&mut self, event: VmEvent<'event>) { + fn add(&mut self, event: VmEvent) { self.tracer.add(event); } } impl<'vm, 'fiber> FiberTracer<'vm, 'fiber> { - fn add<'event>(&mut self, event: FiberEvent<'event>) { + fn add(&mut self, event: FiberEvent) { self.vm_tracer.add(VmEvent::InFiber { fiber: self.fiber, event, diff --git a/compiler/src/vm/use_module.rs b/compiler/src/vm/use_module.rs index 8343ead59..d243a82d5 100644 --- a/compiler/src/vm/use_module.rs +++ b/compiler/src/vm/use_module.rs @@ -34,7 +34,7 @@ impl Fiber { let address = self.heap.create_closure(module_closure); self.data_stack.push(address); self.run_instruction( - &mut PanickingUseProvider, + &PanickingUseProvider, &mut DummyTracer.for_vm().for_fiber(FiberId::root()), Instruction::Call { num_args: 0 }, ); From 5f4b6968e50b29dafbc8633f2b7edf6ab1d5d814 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sun, 30 Oct 2022 22:05:42 +0100 Subject: [PATCH 35/44] Update compiler/src/vm/tracer/mod.rs Co-authored-by: Jonas Wanke --- compiler/src/vm/tracer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index a0d5bb029..af243f5bc 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -106,7 +106,7 @@ impl<'vm> VmTracer<'vm> { } } -impl<'vm> VmTracer<'vm> { +impl<'vm> Tracer for VmTracer<'vm> { fn add(&mut self, event: VmEvent) { self.tracer.add(event); } From 8a9b4923f4f90bd25277e3e644aabc9972365406 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sun, 30 Oct 2022 22:05:49 +0100 Subject: [PATCH 36/44] Update compiler/src/vm/tracer/mod.rs Co-authored-by: Jonas Wanke --- compiler/src/vm/tracer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index af243f5bc..1ae3f0b1a 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -120,7 +120,7 @@ impl<'vm, 'fiber> FiberTracer<'vm, 'fiber> { } } -impl<'vm> VmTracer<'vm> { +impl Tracer { pub fn fiber_created(&mut self, fiber: FiberId) { self.add(VmEvent::FiberCreated { fiber }); } From 930b4d046ef497c48292c73fcbb6503fdc2f3d8b Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Sun, 30 Oct 2022 22:05:57 +0100 Subject: [PATCH 37/44] Update compiler/src/vm/tracer/full.rs Co-authored-by: Jonas Wanke --- compiler/src/vm/tracer/full.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/vm/tracer/full.rs b/compiler/src/vm/tracer/full.rs index d2797958f..952bee1b9 100644 --- a/compiler/src/vm/tracer/full.rs +++ b/compiler/src/vm/tracer/full.rs @@ -190,7 +190,7 @@ impl fmt::Debug for FullTracer { for event in &self.events { writeln!( f, - "{:?} us: {}", + "{:?} µs: {}", event.when.duration_since(start.unwrap()).as_micros(), match &event.event { StoredVmEvent::FiberCreated { fiber } => format!("{fiber:?}: created"), From 939a5e88b974aad39a547a2302f0fa3af4b08eb2 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 31 Oct 2022 10:01:10 +0100 Subject: [PATCH 38/44] Add Cargo workspace --- .gitignore | 4 ++++ Cargo.toml | 5 +++++ 2 files changed, 9 insertions(+) create mode 100644 Cargo.toml diff --git a/.gitignore b/.gitignore index 8b96f8cf1..b769a1215 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,10 @@ local/ # ANTLR .antlr/ +# Rust +target +Cargo.lock + # Dart/Pub **/doc/api/ .dart_tool/ diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..529c35d97 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,5 @@ +[workspace] + +members = [ + "compiler", +] From 85849297ef7049e26b8d9bc9438ddec2df4efc48 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 31 Oct 2022 10:01:16 +0100 Subject: [PATCH 39/44] Move tracer methods --- compiler/src/vm/tracer/mod.rs | 51 +++++++++++++++++------------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index 1ae3f0b1a..0b8e9612a 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -78,6 +78,31 @@ pub enum FiberEvent<'event> { pub trait Tracer { fn add(&mut self, event: VmEvent); + fn fiber_created(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberCreated { fiber }); + } + fn fiber_done(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberDone { fiber }); + } + fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option) { + self.add(VmEvent::FiberPanicked { + fiber, + panicked_child, + }); + } + fn fiber_canceled(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberCanceled { fiber }); + } + fn fiber_execution_started(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberExecutionStarted { fiber }); + } + fn fiber_execution_ended(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberExecutionEnded { fiber }); + } + fn channel_created(&mut self, channel: ChannelId) { + self.add(VmEvent::ChannelCreated { channel }); + } + fn for_vm<'a, 'vm>(&'a mut self) -> VmTracer<'vm> where Self: Sized, @@ -120,32 +145,6 @@ impl<'vm, 'fiber> FiberTracer<'vm, 'fiber> { } } -impl Tracer { - pub fn fiber_created(&mut self, fiber: FiberId) { - self.add(VmEvent::FiberCreated { fiber }); - } - pub fn fiber_done(&mut self, fiber: FiberId) { - self.add(VmEvent::FiberDone { fiber }); - } - pub fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option) { - self.add(VmEvent::FiberPanicked { - fiber, - panicked_child, - }); - } - pub fn fiber_canceled(&mut self, fiber: FiberId) { - self.add(VmEvent::FiberCanceled { fiber }); - } - pub fn fiber_execution_started(&mut self, fiber: FiberId) { - self.add(VmEvent::FiberExecutionStarted { fiber }); - } - pub fn fiber_execution_ended(&mut self, fiber: FiberId) { - self.add(VmEvent::FiberExecutionEnded { fiber }); - } - pub fn channel_created(&mut self, channel: ChannelId) { - self.add(VmEvent::ChannelCreated { channel }); - } -} impl<'vm, 'fiber> FiberTracer<'vm, 'fiber> { pub fn module_started(&mut self, module: Module) { self.add(FiberEvent::ModuleStarted { module }); From 2724256dcb439c695b8bdc4846f0aa06076e4db7 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 31 Oct 2022 10:06:49 +0100 Subject: [PATCH 40/44] Move tracer methods --- compiler/src/vm/tracer/mod.rs | 51 ++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index 0b8e9612a..af243f5bc 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -78,31 +78,6 @@ pub enum FiberEvent<'event> { pub trait Tracer { fn add(&mut self, event: VmEvent); - fn fiber_created(&mut self, fiber: FiberId) { - self.add(VmEvent::FiberCreated { fiber }); - } - fn fiber_done(&mut self, fiber: FiberId) { - self.add(VmEvent::FiberDone { fiber }); - } - fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option) { - self.add(VmEvent::FiberPanicked { - fiber, - panicked_child, - }); - } - fn fiber_canceled(&mut self, fiber: FiberId) { - self.add(VmEvent::FiberCanceled { fiber }); - } - fn fiber_execution_started(&mut self, fiber: FiberId) { - self.add(VmEvent::FiberExecutionStarted { fiber }); - } - fn fiber_execution_ended(&mut self, fiber: FiberId) { - self.add(VmEvent::FiberExecutionEnded { fiber }); - } - fn channel_created(&mut self, channel: ChannelId) { - self.add(VmEvent::ChannelCreated { channel }); - } - fn for_vm<'a, 'vm>(&'a mut self) -> VmTracer<'vm> where Self: Sized, @@ -145,6 +120,32 @@ impl<'vm, 'fiber> FiberTracer<'vm, 'fiber> { } } +impl<'vm> VmTracer<'vm> { + pub fn fiber_created(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberCreated { fiber }); + } + pub fn fiber_done(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberDone { fiber }); + } + pub fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option) { + self.add(VmEvent::FiberPanicked { + fiber, + panicked_child, + }); + } + pub fn fiber_canceled(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberCanceled { fiber }); + } + pub fn fiber_execution_started(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberExecutionStarted { fiber }); + } + pub fn fiber_execution_ended(&mut self, fiber: FiberId) { + self.add(VmEvent::FiberExecutionEnded { fiber }); + } + pub fn channel_created(&mut self, channel: ChannelId) { + self.add(VmEvent::ChannelCreated { channel }); + } +} impl<'vm, 'fiber> FiberTracer<'vm, 'fiber> { pub fn module_started(&mut self, module: Module) { self.add(FiberEvent::ModuleStarted { module }); From 4644a9548b96ac735661fd69d171aa0a0b21b9d3 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 31 Oct 2022 13:05:53 +0100 Subject: [PATCH 41/44] Refactor tracer --- compiler/src/fuzzer/fuzzer.rs | 4 +- compiler/src/fuzzer/mod.rs | 3 +- .../hints/constant_evaluator.rs | 3 +- compiler/src/main.rs | 7 +- compiler/src/vm/builtin_functions.rs | 2 +- compiler/src/vm/fiber.rs | 2 +- compiler/src/vm/mod.rs | 24 ++--- compiler/src/vm/tracer/mod.rs | 91 ++++++++----------- compiler/src/vm/use_module.rs | 2 +- 9 files changed, 62 insertions(+), 76 deletions(-) diff --git a/compiler/src/fuzzer/fuzzer.rs b/compiler/src/fuzzer/fuzzer.rs index 7391aeca9..9efb303b6 100644 --- a/compiler/src/fuzzer/fuzzer.rs +++ b/compiler/src/fuzzer/fuzzer.rs @@ -4,7 +4,7 @@ use crate::{ vm::{ self, context::{ExecutionController, UseProvider}, - tracer::{full::FullTracer, Tracer}, + tracer::full::FullTracer, Closure, Heap, Packet, Pointer, Vm, }, }; @@ -102,7 +102,7 @@ impl Fuzzer { match status { Status::StillFuzzing { mut vm, arguments, mut tracer } => match vm.status() { vm::Status::CanRun => { - vm.run(use_provider, execution_controller, &mut tracer.for_vm()); + vm.run(use_provider, execution_controller, &mut tracer); Status::StillFuzzing { vm, arguments, tracer } } vm::Status::WaitingForOperations => panic!("Fuzzing should not have to wait on channel operations because arguments were not channels."), diff --git a/compiler/src/fuzzer/mod.rs b/compiler/src/fuzzer/mod.rs index 06affdfe0..c20bb366f 100644 --- a/compiler/src/fuzzer/mod.rs +++ b/compiler/src/fuzzer/mod.rs @@ -12,7 +12,6 @@ use crate::{ module::Module, vm::{ context::{DbUseProvider, RunForever, RunLimitedNumberOfInstructions}, - tracer::Tracer, Closure, Heap, Pointer, Vm, }, }; @@ -24,7 +23,7 @@ pub async fn fuzz(db: &Database, module: Module) { let mut tracer = FuzzablesFinder::default(); let mut vm = Vm::new(); vm.set_up_for_running_module_closure(Closure::of_module(db, module).unwrap()); - vm.run(&DbUseProvider { db }, &mut RunForever, &mut tracer.for_vm()); + vm.run(&DbUseProvider { db }, &mut RunForever, &mut tracer); (tracer.heap, tracer.fuzzables) }; diff --git a/compiler/src/language_server/hints/constant_evaluator.rs b/compiler/src/language_server/hints/constant_evaluator.rs index 77e5974d0..42372d1f6 100644 --- a/compiler/src/language_server/hints/constant_evaluator.rs +++ b/compiler/src/language_server/hints/constant_evaluator.rs @@ -15,7 +15,6 @@ use crate::{ tracer::{ full::{FullTracer, StoredFiberEvent, StoredVmEvent, TimedEvent}, stack_trace::StackEntry, - Tracer, }, Closure, FiberId, Heap, Pointer, Vm, }, @@ -63,7 +62,7 @@ impl ConstantEvaluator { evaluator.vm.run( &DbUseProvider { db }, &mut RunLimitedNumberOfInstructions::new(500), - &mut evaluator.tracer.for_vm(), + &mut evaluator.tracer, ); Some(module.clone()) } else { diff --git a/compiler/src/main.rs b/compiler/src/main.rs index 83cae7fd8..33177c857 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -217,7 +217,7 @@ fn run(options: CandyRunOptions) { vm.run( &DbUseProvider { db: &db }, &mut RunForever, - &mut tracer.for_vm(), + &mut tracer, ); if let Status::WaitingForOperations = vm.status() { error!("The module waits on channel operations. Perhaps, the code tried to read from a channel without sending a packet into it."); @@ -277,7 +277,7 @@ fn run(options: CandyRunOptions) { let stdout_port = heap.create_send_port(stdout.channel); heap.create_struct(HashMap::from([(stdout_symbol, stdout_port)])) }; - tracer.for_vm().for_fiber(FiberId::root()).call_started( + tracer.for_fiber(FiberId::root()).call_started( Id::new(module, vec!["main".to_string()]), main, vec![environment], @@ -291,7 +291,7 @@ fn run(options: CandyRunOptions) { vm.run( &DbUseProvider { db: &db }, &mut RunForever, - &mut tracer.for_vm(), + &mut tracer, ); } Status::WaitingForOperations => { @@ -307,7 +307,6 @@ fn run(options: CandyRunOptions) { match vm.tear_down() { ExecutionResult::Finished(return_value) => { tracer - .for_vm() .for_fiber(FiberId::root()) .call_ended(return_value.address, &return_value.heap); debug!("The main function returned: {return_value:?}"); diff --git a/compiler/src/vm/builtin_functions.rs b/compiler/src/vm/builtin_functions.rs index be2a72d8a..2398a0b34 100644 --- a/compiler/src/vm/builtin_functions.rs +++ b/compiler/src/vm/builtin_functions.rs @@ -68,7 +68,7 @@ impl Fiber { self.data_stack.push(closure); self.run_instruction( &PanickingUseProvider, - &mut DummyTracer.for_vm().for_fiber(FiberId::root()), + &mut DummyTracer.for_fiber(FiberId::root()), Instruction::Call { num_args: 0 }, ); } diff --git a/compiler/src/vm/fiber.rs b/compiler/src/vm/fiber.rs index 823a517d1..6a5ed3e65 100644 --- a/compiler/src/vm/fiber.rs +++ b/compiler/src/vm/fiber.rs @@ -129,7 +129,7 @@ impl Fiber { fiber.status = Status::Running; fiber.run_instruction( &PanickingUseProvider, - &mut DummyTracer.for_vm().for_fiber(FiberId::root()), + &mut DummyTracer.for_fiber(FiberId::root()), Instruction::Call { num_args: 0 }, ); fiber diff --git a/compiler/src/vm/mod.rs b/compiler/src/vm/mod.rs index 902d242a7..9d43767a9 100644 --- a/compiler/src/vm/mod.rs +++ b/compiler/src/vm/mod.rs @@ -21,7 +21,7 @@ use self::{ }, heap::SendPort, ids::{CountableId, IdGenerator}, - tracer::VmTracer, + tracer::Tracer, }; use crate::compiler::hir::Id; use itertools::Itertools; @@ -222,9 +222,9 @@ impl Vm { // This will be used as soon as the outside world tries to send something // into the VM. #[allow(dead_code)] - pub fn send( + pub fn send( &mut self, - tracer: &mut VmTracer, + tracer: &mut T, channel: ChannelId, packet: Packet, ) -> OperationId { @@ -246,11 +246,11 @@ impl Vm { self.unreferenced_channels.remove(&channel); } - pub fn run( + pub fn run( &mut self, use_provider: &U, execution_controller: &mut E, - tracer: &mut VmTracer, + tracer: &mut T, ) { while self.can_run() && execution_controller.should_continue_running() { self.run_raw( @@ -263,11 +263,11 @@ impl Vm { ); } } - fn run_raw( + fn run_raw( &mut self, use_provider: &U, execution_controller: &mut E, - tracer: &mut VmTracer, + tracer: &mut T, ) { assert!( self.can_run(), @@ -467,9 +467,9 @@ impl Vm { .collect(); self.unreferenced_channels = unreferenced_channels; } - fn finish_parallel( + fn finish_parallel( &mut self, - tracer: &mut VmTracer, + tracer: &mut T, parallel_id: FiberId, cause: Performer, result: Result<(), String>, @@ -506,7 +506,7 @@ impl Vm { }, ); } - fn cancel(&mut self, tracer: &mut VmTracer, fiber: FiberId) { + fn cancel(&mut self, tracer: &mut dyn Tracer, fiber: FiberId) { match self.fibers.remove(&fiber).unwrap() { FiberTree::Single(_) => {} FiberTree::Parallel(Parallel { @@ -526,9 +526,9 @@ impl Vm { tracer.fiber_canceled(fiber); } - fn send_to_channel( + fn send_to_channel( &mut self, - tracer: &mut VmTracer, + tracer: &mut T, performer: Performer, channel_id: ChannelId, packet: Packet, diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index af243f5bc..30b9166a9 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -78,75 +78,64 @@ pub enum FiberEvent<'event> { pub trait Tracer { fn add(&mut self, event: VmEvent); - fn for_vm<'a, 'vm>(&'a mut self) -> VmTracer<'vm> - where - Self: Sized, - 'a: 'vm, - { - VmTracer::<'vm> { tracer: self } - } -} -pub struct VmTracer<'vm> { - tracer: &'vm mut dyn Tracer, -} -pub struct FiberTracer<'vm, 'fiber> { - vm_tracer: &'fiber mut VmTracer<'vm>, - fiber: FiberId, -} - -impl<'vm> VmTracer<'vm> { - pub fn for_fiber<'fiber>(&'fiber mut self, fiber: FiberId) -> FiberTracer<'vm, 'fiber> - where - Self: 'fiber, - { - FiberTracer { - vm_tracer: self, - fiber, - } - } -} - -impl<'vm> Tracer for VmTracer<'vm> { - fn add(&mut self, event: VmEvent) { - self.tracer.add(event); - } -} -impl<'vm, 'fiber> FiberTracer<'vm, 'fiber> { - fn add(&mut self, event: FiberEvent) { - self.vm_tracer.add(VmEvent::InFiber { - fiber: self.fiber, - event, - }); - } -} - -impl<'vm> VmTracer<'vm> { - pub fn fiber_created(&mut self, fiber: FiberId) { + fn fiber_created(&mut self, fiber: FiberId) { self.add(VmEvent::FiberCreated { fiber }); } - pub fn fiber_done(&mut self, fiber: FiberId) { + fn fiber_done(&mut self, fiber: FiberId) { self.add(VmEvent::FiberDone { fiber }); } - pub fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option) { + fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option) { self.add(VmEvent::FiberPanicked { fiber, panicked_child, }); } - pub fn fiber_canceled(&mut self, fiber: FiberId) { + fn fiber_canceled(&mut self, fiber: FiberId) { self.add(VmEvent::FiberCanceled { fiber }); } - pub fn fiber_execution_started(&mut self, fiber: FiberId) { + fn fiber_execution_started(&mut self, fiber: FiberId) { self.add(VmEvent::FiberExecutionStarted { fiber }); } - pub fn fiber_execution_ended(&mut self, fiber: FiberId) { + fn fiber_execution_ended(&mut self, fiber: FiberId) { self.add(VmEvent::FiberExecutionEnded { fiber }); } - pub fn channel_created(&mut self, channel: ChannelId) { + fn channel_created(&mut self, channel: ChannelId) { self.add(VmEvent::ChannelCreated { channel }); } + + // fn in_fiber_tracer<'a>(&'a mut self, fiber: FiberId) -> Box + 'a> + // where + // Self: 'a, + // { + // Box::new(FullInFiberTracer { + // tracer: self, + // fiber, + // }) + // } + + fn for_fiber<'a, 'fiber>(&'a mut self, fiber: FiberId) -> FiberTracer<'fiber> + where + Self: Sized, + 'a: 'fiber, + { + FiberTracer::<'fiber> { + tracer: self, + fiber, + } + } } -impl<'vm, 'fiber> FiberTracer<'vm, 'fiber> { +pub struct FiberTracer<'fiber> { + tracer: &'fiber mut dyn Tracer, + fiber: FiberId, +} +impl<'fiber> FiberTracer<'fiber> { + fn add(&mut self, event: FiberEvent) { + self.tracer.add(VmEvent::InFiber { + fiber: self.fiber, + event, + }); + } + pub fn module_started(&mut self, module: Module) { self.add(FiberEvent::ModuleStarted { module }); } diff --git a/compiler/src/vm/use_module.rs b/compiler/src/vm/use_module.rs index d243a82d5..e05754717 100644 --- a/compiler/src/vm/use_module.rs +++ b/compiler/src/vm/use_module.rs @@ -35,7 +35,7 @@ impl Fiber { self.data_stack.push(address); self.run_instruction( &PanickingUseProvider, - &mut DummyTracer.for_vm().for_fiber(FiberId::root()), + &mut DummyTracer.for_fiber(FiberId::root()), Instruction::Call { num_args: 0 }, ); } From 5ba00afd439c1550ef4a22e532ab0276bc419a00 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 31 Oct 2022 13:07:35 +0100 Subject: [PATCH 42/44] Format main --- compiler/src/main.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/compiler/src/main.rs b/compiler/src/main.rs index 33177c857..1d8cd9ae1 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -214,11 +214,7 @@ fn run(options: CandyRunOptions) { let mut vm = Vm::new(); vm.set_up_for_running_module_closure(module_closure); - vm.run( - &DbUseProvider { db: &db }, - &mut RunForever, - &mut tracer, - ); + vm.run(&DbUseProvider { db: &db }, &mut RunForever, &mut tracer); if let Status::WaitingForOperations = vm.status() { error!("The module waits on channel operations. Perhaps, the code tried to read from a channel without sending a packet into it."); // TODO: Show stack traces of all fibers? @@ -288,11 +284,7 @@ fn run(options: CandyRunOptions) { match vm.status() { Status::CanRun => { debug!("VM still running."); - vm.run( - &DbUseProvider { db: &db }, - &mut RunForever, - &mut tracer, - ); + vm.run(&DbUseProvider { db: &db }, &mut RunForever, &mut tracer); } Status::WaitingForOperations => { todo!("VM can't proceed until some operations complete."); From 35b5c3bd654ed19b6a4f5e58c3d25c00e8a80963 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 31 Oct 2022 13:28:38 +0100 Subject: [PATCH 43/44] Update .gitignores and lock files --- .gitignore | 5 +- compiler/Cargo.lock => Cargo.lock | 596 +++++++++++++++++++----------- compiler/.gitignore | 3 - 3 files changed, 391 insertions(+), 213 deletions(-) rename compiler/Cargo.lock => Cargo.lock (72%) delete mode 100644 compiler/.gitignore diff --git a/.gitignore b/.gitignore index b769a1215..1938ad440 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,10 @@ local/ # Rust target -Cargo.lock + +# Perf +**/perf.data +**/perf.data.old # Dart/Pub **/doc/api/ diff --git a/compiler/Cargo.lock b/Cargo.lock similarity index 72% rename from compiler/Cargo.lock rename to Cargo.lock index d7460d32c..626d4574f 100644 --- a/compiler/Cargo.lock +++ b/Cargo.lock @@ -4,13 +4,22 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" dependencies = [ "memchr", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -22,9 +31,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.56" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" +checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" dependencies = [ "proc-macro2", "quote", @@ -62,9 +71,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bit-set" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ "bit-vec", ] @@ -90,6 +99,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + [[package]] name = "byteorder" version = "1.4.3" @@ -98,9 +113,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "candy" @@ -136,6 +151,12 @@ dependencies = [ "url", ] +[[package]] +name = "cc" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574" + [[package]] name = "cfg-if" version = "0.1.10" @@ -150,14 +171,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" dependencies = [ - "libc", + "iana-time-zone", + "js-sys", "num-integer", "num-traits", "time", + "wasm-bindgen", "winapi 0.3.9", ] @@ -176,6 +199,16 @@ dependencies = [ "vec_map", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "colored" version = "2.0.0" @@ -187,51 +220,103 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "cxx" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dashmap" -version = "5.3.3" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391b56fbd302e585b7a9494fb70e40949567b1cf9003a8e4a6041a1687c26573" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if 1.0.0", - "hashbrown 0.12.1", + "hashbrown", "lock_api", + "once_cell", + "parking_lot_core 0.9.4", ] [[package]] name = "either" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "fastrand" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] [[package]] name = "filetime" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall", - "winapi 0.3.9", + "windows-sys", ] [[package]] @@ -242,11 +327,10 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ - "matches", "percent-encoding", ] @@ -287,9 +371,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" dependencies = [ "futures-channel", "futures-core", @@ -301,9 +385,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" dependencies = [ "futures-core", "futures-sink", @@ -311,21 +395,21 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ "proc-macro2", "quote", @@ -334,21 +418,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" dependencies = [ "futures-channel", "futures-core", @@ -364,26 +448,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.10.0+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "hashbrown" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" @@ -411,17 +489,40 @@ dependencies = [ [[package]] name = "httparse" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6330e8a36bd8c859f3fa6d9382911fbb7147ec39807f63b923933a247240b9ba" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi 0.3.9", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] [[package]] name = "idna" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" dependencies = [ - "matches", "unicode-bidi", "unicode-normalization", ] @@ -442,12 +543,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.1" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown 0.11.2", + "hashbrown", ] [[package]] @@ -490,18 +591,27 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "js-sys" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] [[package]] name = "kernel32-sys" @@ -527,21 +637,30 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.122" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "link-cplusplus" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] [[package]] name = "linked-hash-map" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", @@ -549,18 +668,18 @@ dependencies = [ [[package]] name = "log" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "lsp-types" -version = "0.93.0" +version = "0.93.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70c74e2173b2b31f8655d33724b4b45ac13f439386f66290f539c22b144c2212" +checksum = "9be6e9c7e2d18f651974370d7aff703f9513e0df6e464fd795660edc77e6ca51" dependencies = [ "bitflags", "serde", @@ -578,17 +697,11 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mio" @@ -603,7 +716,7 @@ dependencies = [ "kernel32-sys", "libc", "log", - "miow 0.2.2", + "miow", "net2", "slab", "winapi 0.2.8", @@ -611,16 +724,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", - "miow 0.3.7", - "ntapi", "wasi 0.11.0+wasi-snapshot-preview1", - "winapi 0.3.9", + "windows-sys", ] [[package]] @@ -647,20 +758,11 @@ dependencies = [ "ws2_32-sys", ] -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi 0.3.9", -] - [[package]] name = "net2" -version = "0.2.37" +version = "0.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +checksum = "74d0df99cfcd2530b2e694f6e17e7f37b8e26bb23983ac530c0c97408837c631" dependencies = [ "cfg-if 0.1.10", "libc", @@ -685,15 +787,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "ntapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" -dependencies = [ - "winapi 0.3.9", -] - [[package]] name = "num-bigint" version = "0.4.3" @@ -737,9 +830,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "oorandom" @@ -769,12 +862,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.2", + "parking_lot_core 0.9.4", ] [[package]] @@ -793,9 +886,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ "cfg-if 1.0.0", "libc", @@ -806,24 +899,24 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pin-project" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", @@ -832,9 +925,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -874,9 +967,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -915,9 +1008,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quote" -version = "1.0.18" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -945,9 +1038,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] @@ -972,18 +1065,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.5" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -1001,9 +1094,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "remove_dir_all" @@ -1022,9 +1115,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustversion" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" [[package]] name = "rusty-fork" @@ -1040,9 +1133,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "salsa" @@ -1088,20 +1181,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "serde" -version = "1.0.137" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ "proc-macro2", "quote", @@ -1110,9 +1209,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.80" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f972498cf015f7c0746cac89ebe1d6ef10c293b94175a243a2d9442c163d9944" +checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" dependencies = [ "itoa", "ryu", @@ -1121,9 +1220,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" dependencies = [ "proc-macro2", "quote", @@ -1160,21 +1259,24 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] [[package]] name = "smallvec" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi 0.3.9", @@ -1212,15 +1314,15 @@ dependencies = [ [[package]] name = "strum" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96acfc1b70604b8b2f1ffa4c57e59176c7dbb05d556c71ecd2f5498a1dee7f8" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" [[package]] name = "strum_macros" -version = "0.24.0" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6878079b17446e4d3eba6192bb0a2950d5b14f0ed8424b852310e5a94345d0ef" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.0", "proc-macro2", @@ -1231,9 +1333,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.98" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", @@ -1254,6 +1356,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -1285,9 +1396,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -1300,17 +1411,17 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.18.0" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f48b6d60512a392e34dbf7fd456249fd2de3c83669ab642e021903f4015185b" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" dependencies = [ + "autocfg", "bytes", "libc", "memchr", - "mio 0.8.2", + "mio 0.8.5", "num_cpus", - "once_cell", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", "socket2", @@ -1320,9 +1431,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ "proc-macro2", "quote", @@ -1331,9 +1442,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes", "futures-core", @@ -1345,9 +1456,9 @@ dependencies = [ [[package]] name = "tower" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", @@ -1359,9 +1470,9 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" [[package]] name = "tower-lsp" @@ -1399,15 +1510,15 @@ dependencies = [ [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.34" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -1417,9 +1528,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", @@ -1428,11 +1539,11 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.26" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ - "lazy_static", + "once_cell", "valuable", ] @@ -1487,46 +1598,45 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "url" -version = "2.2.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", "idna", - "matches", "percent-encoding", "serde", ] @@ -1581,6 +1691,60 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + [[package]] name = "winapi" version = "0.2.8" @@ -1626,46 +1790,60 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.34.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ + "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", + "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + [[package]] name = "windows_aarch64_msvc" -version = "0.34.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" [[package]] name = "windows_i686_gnu" -version = "0.34.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" [[package]] name = "windows_i686_msvc" -version = "0.34.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" [[package]] name = "windows_x86_64_gnu" -version = "0.34.0" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" [[package]] name = "windows_x86_64_msvc" -version = "0.34.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" [[package]] name = "ws2_32-sys" diff --git a/compiler/.gitignore b/compiler/.gitignore deleted file mode 100644 index b8a1e0d5d..000000000 --- a/compiler/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -target/ -**/perf.data -**/perf.data.old From 09c9be405e24ba46be6cb751fc3ba4040322eb71 Mon Sep 17 00:00:00 2001 From: Marcel Garus Date: Mon, 31 Oct 2022 13:30:10 +0100 Subject: [PATCH 44/44] Remove commented out code --- compiler/src/vm/tracer/mod.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/compiler/src/vm/tracer/mod.rs b/compiler/src/vm/tracer/mod.rs index 30b9166a9..f819a5a7b 100644 --- a/compiler/src/vm/tracer/mod.rs +++ b/compiler/src/vm/tracer/mod.rs @@ -103,16 +103,6 @@ pub trait Tracer { self.add(VmEvent::ChannelCreated { channel }); } - // fn in_fiber_tracer<'a>(&'a mut self, fiber: FiberId) -> Box + 'a> - // where - // Self: 'a, - // { - // Box::new(FullInFiberTracer { - // tracer: self, - // fiber, - // }) - // } - fn for_fiber<'a, 'fiber>(&'a mut self, fiber: FiberId) -> FiberTracer<'fiber> where Self: Sized,