diff --git a/src/behavior/builder_visitor.rs b/src/behavior/builder_visitor.rs index 8451002a..75622ad5 100644 --- a/src/behavior/builder_visitor.rs +++ b/src/behavior/builder_visitor.rs @@ -7,9 +7,8 @@ use parser_types::{DataType, Whammy, Whamm, WhammVisitor, Expr, Fn, Event, Packa use log::{debug, error, trace}; use regex::Regex; use crate::behavior::tree::ParamActionType; -use crate::behavior::tree::DecoratorType::{HasAltCall, HasParams, PredIs}; +use crate::behavior::tree::DecoratorType::{HasAltCall, PredIs}; use crate::parser::types::Global; -use crate::verifier::types::ScopeType; pub type SimpleAST = HashMap>>>>; @@ -127,35 +126,35 @@ impl BehaviorTreeBuilder { fn visit_bytecode_package(&mut self, package: &Package) { if package.events.len() > 0 { + // Build events->globals HashMap + let mut events = HashMap::new(); + for (event_name, event) in package.events.iter() { + let globals: Vec = event.globals.keys().cloned().collect(); + events.insert(event_name.clone(), globals); + } + self.tree.action_with_child(ActionWithChildType::EnterPackage { - package_name: package.name.clone() - }) - .decorator(DecoratorType::IsInstr { - instr_names: package.events.keys().cloned().collect(), - }); + context: self.context_name.clone(), + package_name: package.name.clone(), + events, + }); for (_name, event) in package.events.iter() { // just grab the first one and emit behavior (the decorator above is what // makes this apply to all events) self.visit_event(event); break; } - self.tree.exit_decorator(); self.tree.exit_action_with_child(); } } fn visit_bytecode_event(&mut self, event: &Event) { - self.tree.sequence() - .enter_scope_of(self.context_name.clone(), ScopeType::Event); - - // Define globals - self.visit_globals(&event.globals); + self.tree.sequence(); self.visit_probe_ty(event, "before"); self.visit_probe_ty(event, "alt"); self.visit_probe_ty(event, "after"); - self.tree.exit_scope(); self.tree.exit_sequence(); } @@ -170,20 +169,14 @@ impl BehaviorTreeBuilder { } fn visit_bytecode_probe(&mut self, probe: &Probe) { - self.tree.fold_pred() - .fallback() + self.tree.fallback() .decorator(PredIs { val: false }) .force_success() .exit_decorator() .sequence() - .fallback() - .decorator(HasParams) - .save_params() - .exit_decorator() - .force_success() - .exit_fallback() + .save_params(true) .fallback() .decorator(PredIs { val: true @@ -198,7 +191,7 @@ impl BehaviorTreeBuilder { .force_success() .exit_fallback() .emit_body() - .emit_params_subtree() + .emit_params(true) .fallback() .decorator(HasAltCall) .emit_alt_call() @@ -258,7 +251,7 @@ impl BehaviorTreeBuilder { .fallback() .decorator(HasAltCall) .sequence() // TODO -- remove need for this (just have normal lib::() call syntax) - .emit_params_subtree() + .emit_params(true) .emit_alt_call() .exit_sequence() .exit_decorator() @@ -266,7 +259,7 @@ impl BehaviorTreeBuilder { .exit_fallback() .exit_sequence() .sequence() - .emit_params_subtree() + .emit_params(true) .emit_orig() .exit_sequence() .exit_parameterized_action() @@ -351,16 +344,12 @@ impl WhammVisitor<()> for BehaviorTreeBuilder { self.context_name += &format!(":{}", package.name.clone()); self.add_package_to_ast(package.name.clone()); - self.tree.enter_scope(self.context_name.clone(), package.name.clone()); - if self.is_in_context(r"whamm:whammy([0-9]+):wasm:bytecode") { self.visit_bytecode_package(package); } else { error!("Unsupported package: {}", package.name); }; - self.tree.exit_scope(); - trace!("Exiting: BehaviorTreeBuilder::visit_package"); // Remove this package from `context_name` self.context_name = self.context_name[..self.context_name.rfind(":").unwrap()].to_string(); @@ -387,20 +376,11 @@ impl WhammVisitor<()> for BehaviorTreeBuilder { self.context_name += &format!(":{}", probe.name.clone()); self.add_probe_to_ast(probe); - if probe.name == "alt" { - self.tree.decorator(DecoratorType::ForFirstProbe { - target: probe.name.clone() - }); - } else { - self.tree.decorator(DecoratorType::ForEachProbe { - target: probe.name.clone() - }); - } - self.tree.sequence() - .enter_scope(self.context_name.clone(), probe.name.clone()); - - // visit globals - self.visit_globals(&probe.globals); + self.tree.action_with_child(ActionWithChildType::EnterProbe { + context: self.context_name.clone(), + probe_name: probe.name.clone(), + global_names: probe.globals.keys().cloned().collect(), + }); if self.is_in_context(r"whamm:whammy([0-9]+):wasm:bytecode:(.*)") { self.visit_bytecode_probe(probe); @@ -408,11 +388,8 @@ impl WhammVisitor<()> for BehaviorTreeBuilder { error!("Unsupported probe: {}", self.context_name); }; - self.tree.exit_scope(); - trace!("Exiting: BehaviorTreeBuilder::visit_probe"); - self.tree.exit_sequence() - .exit_decorator(); + self.tree.exit_action_with_child(); // Remove this probe from `context_name` self.context_name = self.context_name[..self.context_name.rfind(":").unwrap()].to_string(); } diff --git a/src/behavior/tree.rs b/src/behavior/tree.rs index 51376aca..d3798b70 100644 --- a/src/behavior/tree.rs +++ b/src/behavior/tree.rs @@ -1,5 +1,5 @@ +use std::collections::HashMap; use log::error; -use crate::verifier::types::ScopeType; #[derive(Debug)] pub struct BehaviorTree { @@ -137,7 +137,7 @@ impl BehaviorTree { pub fn parameterized_action(&mut self, ty: ParamActionType) -> &mut Self { let id = self.nodes.len(); - self.put_child_and_enter(Node::ParameterizedAction { + self.put_child_and_enter(Node::ActionWithParams { id, parent: self.curr, ty, @@ -148,7 +148,7 @@ impl BehaviorTree { pub fn exit_parameterized_action(&mut self) -> &mut Self { match self.get_curr_mut() { - Some(Node::ParameterizedAction {parent, ..}) => { + Some(Node::ActionWithParams {parent, ..}) => { self.curr = parent.clone() }, other => { @@ -164,7 +164,7 @@ impl BehaviorTree { fn add_action_as_param(&mut self, idx: usize, id: usize) { match self.get_curr_mut() { - Some(Node::ParameterizedAction {ty, ..}) => { + Some(Node::ActionWithParams {ty, ..}) => { match ty { ParamActionType::EmitIf { cond, conseq } => { if idx == 0 { @@ -225,23 +225,26 @@ impl BehaviorTree { self } - pub fn emit_params(&mut self) -> &mut Self { + pub fn emit_params(&mut self, force_success: bool) -> &mut Self { let id = self.nodes.len(); - self.put_child(Node::Action { + self.put_child(Node::ArgAction { id, parent: self.curr, - ty: ActionType::EmitParams + ty: ArgActionType::EmitParams, + force_success, }); self } - pub fn emit_params_subtree(&mut self) -> &mut Self { - self.fallback() - .decorator(DecoratorType::HasParams) - .emit_params() - .exit_decorator() - .force_success() - .exit_fallback() + pub fn save_params(&mut self, force_success: bool) -> &mut Self { + let id = self.nodes.len(); + self.put_child(Node::ArgAction { + id, + parent: self.curr, + ty: ArgActionType::SaveParams, + force_success, + }); + self } pub fn remove_orig(&mut self) -> &mut Self { @@ -274,19 +277,6 @@ impl BehaviorTree { self } - pub fn enter_scope_of(&mut self, context_name: String, scope_ty: ScopeType) -> &mut Self { - let id = self.nodes.len(); - self.put_child(Node::Action { - id, - parent: self.curr, - ty: ActionType::EnterScopeOf { - context: context_name, - scope_ty - } - }); - self - } - pub fn enter_scope(&mut self, context_name: String, scope_name: String) -> &mut Self { let id = self.nodes.len(); self.put_child(Node::Action { @@ -310,16 +300,6 @@ impl BehaviorTree { self } - pub fn fold_pred(&mut self) -> &mut Self { - let id = self.nodes.len(); - self.put_child(Node::Action { - id, - parent: self.curr, - ty: ActionType::FoldPred - }); - self - } - pub fn force_success(&mut self) -> &mut Self { let id = self.nodes.len(); self.put_child(Node::Action { @@ -330,16 +310,6 @@ impl BehaviorTree { self } - pub fn save_params(&mut self) -> &mut Self { - let id = self.nodes.len(); - self.put_child(Node::Action { - id, - parent: self.curr, - ty: ActionType::SaveParams - }); - self - } - // ================== // ==== Base Fns ==== // ================== @@ -370,7 +340,7 @@ impl BehaviorTree { *child = new_id; assigned_id = Some(new_id); } - Node::ParameterizedAction { children, .. } => { + Node::ActionWithParams { children, .. } => { let idx = children.len(); children.push(new_id); @@ -440,13 +410,20 @@ pub enum Node { parent: usize, children: Vec }, + /// An action to perform on arguments to some Wasm function + ArgAction { + id: usize, + ty: ArgActionType, + parent: usize, + force_success: bool + }, ActionWithChild { id: usize, ty: ActionWithChildType, parent: usize, child: usize }, - ParameterizedAction { + ActionWithParams { id: usize, parent: usize, ty: ParamActionType, @@ -461,24 +438,12 @@ pub enum Node { #[derive(Debug)] pub enum DecoratorType { - IsInstr { - instr_names: Vec - }, IsProbeType { probe_type: String }, - HasParams, HasAltCall, PredIs { val: bool - }, - /// Iterates over all probes of the specified name in the list. - ForEachProbe { - target: String - }, - /// Only pulls the first probe of the specified name from the list. - ForFirstProbe { - target: String } } @@ -488,20 +453,13 @@ pub enum ActionType { context: String, scope_name: String }, - EnterScopeOf { - context: String, - scope_ty: ScopeType - }, ExitScope, Define { context: String, var_name: String }, EmitPred, - FoldPred, Reset, - SaveParams, - EmitParams, EmitBody, EmitAltCall, RemoveOrig, @@ -509,11 +467,25 @@ pub enum ActionType { ForceSuccess } +#[derive(Debug)] +pub enum ArgActionType { + SaveParams, + EmitParams +} + #[derive(Debug)] pub enum ActionWithChildType { EnterPackage { - package_name: String + context: String, + package_name: String, + /// The events and the corresponding compiler-defined globals + events: HashMap> }, + EnterProbe { + context: String, + probe_name: String, + global_names: Vec + } } #[derive(Debug)] @@ -537,9 +509,10 @@ pub trait BehaviorVisitor { Node::Sequence { .. } => self.visit_sequence(node), Node::Decorator { .. } => self.visit_decorator(node), Node::Fallback { .. } => self.visit_fallback(node), + Node::ArgAction { .. } => self.visit_arg_action(node), Node::ActionWithChild { .. } => self.visit_action_with_child(node), - Node::ParameterizedAction { .. } => self.visit_parameterized_action(node), - Node::Action { .. } => self.visit_action(node), + Node::ActionWithParams { .. } => self.visit_action_with_params(node), + Node::Action { .. } => self.visit_action(node) } } fn visit_root(&mut self, node: &Node) -> T; @@ -549,30 +522,37 @@ pub trait BehaviorVisitor { fn visit_decorator(&mut self, node: &Node) -> T { if let Node::Decorator { ty, ..} = node { match ty { - DecoratorType::IsInstr {..} => self.visit_is_instr(node), DecoratorType::IsProbeType {..} => self.visit_is_probe_type(node), DecoratorType::HasAltCall {..} => self.visit_has_alt_call(node), - DecoratorType::HasParams {..} => self.visit_has_params(node), - DecoratorType::PredIs {..} => self.visit_pred_is(node), - DecoratorType::ForEachProbe {..} => self.visit_for_each_probe(node), - DecoratorType::ForFirstProbe {..} => self.visit_for_first_probe(node), + DecoratorType::PredIs {..} => self.visit_pred_is(node) } } else { unreachable!() } } fn visit_fallback(&mut self, node: &Node) -> T; + fn visit_arg_action(&mut self, node: &Node) -> T { + if let Node::ArgAction { ty, ..} = node { + match ty { + ArgActionType::SaveParams {..} => self.visit_save_params(node), + ArgActionType::EmitParams {..} => self.visit_emit_params(node), + } + } else { + unreachable!() + } + } fn visit_action_with_child(&mut self, node: &Node) -> T { if let Node::ActionWithChild { ty, ..} = node { match ty { ActionWithChildType::EnterPackage {..} => self.visit_enter_package(node), + ActionWithChildType::EnterProbe {..} => self.visit_enter_probe(node), } } else { unreachable!() } } - fn visit_parameterized_action(&mut self, node: &Node) -> T { - if let Node::ParameterizedAction { ty, ..} = node { + fn visit_action_with_params(&mut self, node: &Node) -> T { + if let Node::ActionWithParams { ty, ..} = node { match ty { ParamActionType::EmitIfElse {..} => self.visit_emit_if_else(node), ParamActionType::EmitIf {..} => self.visit_emit_if(node) @@ -583,16 +563,17 @@ pub trait BehaviorVisitor { } // Decorator nodes - fn visit_is_instr(&mut self, node: &Node) -> T; fn visit_is_probe_type(&mut self, node: &Node) -> T; fn visit_has_alt_call(&mut self, node: &Node) -> T; - fn visit_has_params(&mut self, node: &Node) -> T; fn visit_pred_is(&mut self, node: &Node) -> T; - fn visit_for_each_probe(&mut self, node: &Node) -> T; - fn visit_for_first_probe(&mut self, node: &Node) -> T; + + // Argument action nodes + fn visit_save_params(&mut self, node: &Node) -> T; + fn visit_emit_params(&mut self, node: &Node) -> T; // Action with child nodes fn visit_enter_package(&mut self, node: &Node) -> T; + fn visit_enter_probe(&mut self, node: &Node) -> T; // Parameterized action nodes fn visit_emit_if_else(&mut self, node: &Node) -> T; @@ -603,14 +584,10 @@ pub trait BehaviorVisitor { if let Node::Action { ty, ..} = node { match ty { ActionType::EnterScope {..} => self.visit_enter_scope(node), - ActionType::EnterScopeOf {..} => self.visit_enter_scope_of(node), ActionType::ExitScope {..} => self.visit_exit_scope(node), ActionType::Define {..} => self.visit_define(node), ActionType::EmitPred {..} => self.visit_emit_pred(node), - ActionType::FoldPred {..} => self.visit_fold_pred(node), ActionType::Reset {..} => self.visit_reset(node), - ActionType::SaveParams {..} => self.visit_save_params(node), - ActionType::EmitParams {..} => self.visit_emit_params(node), ActionType::EmitBody {..} => self.visit_emit_body(node), ActionType::EmitAltCall {..} => self.visit_emit_alt_call(node), ActionType::RemoveOrig {..} => self.visit_remove_orig(node), @@ -622,14 +599,10 @@ pub trait BehaviorVisitor { } } fn visit_enter_scope(&mut self, node: &Node) -> T; - fn visit_enter_scope_of(&mut self, node: &Node) -> T; fn visit_exit_scope(&mut self, node: &Node) -> T; fn visit_define(&mut self, node: &Node) -> T; fn visit_emit_pred(&mut self, node: &Node) -> T; - fn visit_fold_pred(&mut self, node: &Node) -> T; fn visit_reset(&mut self, node: &Node) -> T; - fn visit_save_params(&mut self, node: &Node) -> T; - fn visit_emit_params(&mut self, node: &Node) -> T; fn visit_emit_body(&mut self, node: &Node) -> T; fn visit_emit_alt_call(&mut self, node: &Node) -> T; fn visit_remove_orig(&mut self, node: &Node) -> T; diff --git a/src/behavior/visualize.rs b/src/behavior/visualize.rs index 1dc478e0..05b58c6b 100644 --- a/src/behavior/visualize.rs +++ b/src/behavior/visualize.rs @@ -5,7 +5,7 @@ use graphviz_rust::exec; use graphviz_rust::dot_structures::{Attribute, Edge, EdgeTy, Graph, Id, Node, NodeId, Stmt, Vertex}; use graphviz_rust::dot_generator::{attr, edge, graph, id, node, node_id, stmt}; use graphviz_rust::printer::PrinterContext; -use crate::behavior::tree::{ActionType, ActionWithChildType, BehaviorTree, BehaviorVisitor, DecoratorType, Node as TreeNode, ParamActionType}; +use crate::behavior::tree::{ActionType, ActionWithChildType, ArgActionType, BehaviorTree, BehaviorVisitor, DecoratorType, Node as TreeNode, ParamActionType}; pub fn visualization_to_file(tree: &BehaviorTree, path: PathBuf) -> Result> { let graph = visualize(tree); @@ -151,31 +151,6 @@ impl BehaviorVisitor<()> for Visualizer<'_> { } } - fn visit_is_instr(&mut self, node: &TreeNode) -> () { - if let TreeNode::Decorator { id, ty, parent, child } = node { - if let DecoratorType::IsInstr {instr_names} = ty { - let mut names = "".to_string(); - for name in instr_names { - if names.is_empty() { - names.push_str(name); - } else { - names.push_str(&format!("OR{name}")); - } - } - self.emit_decorator_node(id, &format!("IsInstr_{}", names)); - self.emit_edge(parent, id); - - if let Some(node) = self.tree.get_node(child.clone()) { - self.visit_node(node); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - fn visit_is_probe_type(&mut self, node: &TreeNode) -> () { if let TreeNode::Decorator { id, ty, parent, child } = node { if let DecoratorType::IsProbeType {probe_type} = ty { @@ -210,10 +185,10 @@ impl BehaviorVisitor<()> for Visualizer<'_> { } } - fn visit_has_params(&mut self, node: &TreeNode) -> () { + fn visit_pred_is(&mut self, node: &TreeNode) -> () { if let TreeNode::Decorator { id, ty, parent, child } = node { - if let DecoratorType::HasParams = ty { - self.emit_decorator_node(id, "HasParams"); + if let DecoratorType::PredIs{ val } = ty { + self.emit_decorator_node(id, &format!("PredIs_{}", val)); self.emit_edge(parent, id); if let Some(node) = self.tree.get_node(child.clone()) { @@ -227,15 +202,11 @@ impl BehaviorVisitor<()> for Visualizer<'_> { } } - fn visit_pred_is(&mut self, node: &TreeNode) -> () { - if let TreeNode::Decorator { id, ty, parent, child } = node { - if let DecoratorType::PredIs{ val } = ty { - self.emit_decorator_node(id, &format!("PredIs_{}", val)); + fn visit_save_params(&mut self, node: &TreeNode) -> () { + if let TreeNode::ArgAction {id, ty, parent, ..} = node { + if let ArgActionType::SaveParams = ty { + self.emit_special_action_node(id, "SaveParams"); self.emit_edge(parent, id); - - if let Some(node) = self.tree.get_node(child.clone()) { - self.visit_node(node); - } } else { unreachable!() } @@ -244,15 +215,11 @@ impl BehaviorVisitor<()> for Visualizer<'_> { } } - fn visit_for_each_probe(&mut self, node: &TreeNode) -> () { - if let TreeNode::Decorator { id, ty, parent, child } = node { - if let DecoratorType::ForEachProbe { target } = ty { - self.emit_decorator_node(id, &format!("ForEachProbe_{}", target.replace(":", "_"))); + fn visit_emit_params(&mut self, node: &TreeNode) -> () { + if let TreeNode::ArgAction { id, ty, parent, ..} = node { + if let ArgActionType::EmitParams = ty { + self.emit_special_action_node(id, "EmitParams"); self.emit_edge(parent, id); - - if let Some(node) = self.tree.get_node(child.clone()) { - self.visit_node(node); - } } else { unreachable!() } @@ -261,31 +228,38 @@ impl BehaviorVisitor<()> for Visualizer<'_> { } } - fn visit_for_first_probe(&mut self, node: &TreeNode) -> () { - if let TreeNode::Decorator { id, ty, parent, child } = node { - if let DecoratorType::ForFirstProbe { target } = ty { - self.emit_decorator_node(id, &format!("ForFirstProbe_{}", target.replace(":", "_"))); + fn visit_enter_package(&mut self, node: &TreeNode) -> () { + if let TreeNode::ActionWithChild { id, ty, parent, child } = node { + if let ActionWithChildType::EnterPackage { package_name, events, .. } = ty { + let mut event_names = "".to_string(); + events.keys().for_each(|event_name| { + if event_names.is_empty() { + event_names.push_str(event_name); + } else { + event_names.push_str(&format!("OR{event_name}")); + } + }); + self.emit_special_action_node(id, &format!("EnterPackage_{}_{}", package_name.replace(":", "_"), event_names)); self.emit_edge(parent, id); if let Some(node) = self.tree.get_node(child.clone()) { self.visit_node(node); } - } else { - unreachable!() } } else { unreachable!() } } - fn visit_enter_package(&mut self, node: &TreeNode) -> () { + fn visit_enter_probe(&mut self, node: &TreeNode) -> () { if let TreeNode::ActionWithChild { id, ty, parent, child } = node { - let ActionWithChildType::EnterPackage { package_name } = ty; - self.emit_special_action_node(id, &format!("EnterPackage_{}", package_name.replace(":", "_"))); - self.emit_edge(parent, id); + if let ActionWithChildType::EnterProbe { probe_name, .. } = ty { + self.emit_special_action_node(id, &format!("EnterProbe_{}", probe_name.replace(":", "_"))); + self.emit_edge(parent, id); - if let Some(node) = self.tree.get_node(child.clone()) { - self.visit_node(node); + if let Some(node) = self.tree.get_node(child.clone()) { + self.visit_node(node); + } } } else { unreachable!() @@ -293,7 +267,7 @@ impl BehaviorVisitor<()> for Visualizer<'_> { } fn visit_emit_if_else(&mut self, node: &TreeNode) -> () { - if let TreeNode::ParameterizedAction { id, parent, ty, .. } = node { + if let TreeNode::ActionWithParams { id, parent, ty, .. } = node { if let ParamActionType::EmitIfElse { cond, conseq, alt } = ty { self.emit_special_action_node(id, "EmitIfElse"); self.emit_edge(parent, id); @@ -322,7 +296,7 @@ impl BehaviorVisitor<()> for Visualizer<'_> { } fn visit_emit_if(&mut self, node: &TreeNode) -> () { - if let TreeNode::ParameterizedAction { id, parent, ty, .. } = node { + if let TreeNode::ActionWithParams { id, parent, ty, .. } = node { if let ParamActionType::EmitIf { cond, conseq } = ty { self.emit_special_action_node(id, "EmitIf"); self.emit_edge(parent, id); @@ -358,19 +332,6 @@ impl BehaviorVisitor<()> for Visualizer<'_> { } } - fn visit_enter_scope_of(&mut self, node: &TreeNode) -> () { - if let TreeNode::Action { id, ty, parent} = node { - if let ActionType::EnterScopeOf{ scope_ty, .. } = ty { - self.emit_action_node(id, &format!("EnterScopeOf_{}", scope_ty.to_string())); - self.emit_edge(parent, id); - } else { - unreachable!() - } - } else { - unreachable!() - } - } - fn visit_exit_scope(&mut self, node: &TreeNode) -> () { if let TreeNode::Action { id, ty, parent} = node { if let ActionType::ExitScope = ty { @@ -410,19 +371,6 @@ impl BehaviorVisitor<()> for Visualizer<'_> { } } - fn visit_fold_pred(&mut self, node: &TreeNode) -> () { - if let TreeNode::Action { id, ty, parent} = node { - if let ActionType::FoldPred = ty { - self.emit_action_node(id, "FoldPred"); - self.emit_edge(parent, id); - } else { - unreachable!() - } - } else { - unreachable!() - } - } - fn visit_reset(&mut self, node: &TreeNode) -> () { if let TreeNode::Action { id, ty, parent} = node { if let ActionType::Reset = ty { @@ -436,32 +384,6 @@ impl BehaviorVisitor<()> for Visualizer<'_> { } } - fn visit_save_params(&mut self, node: &TreeNode) -> () { - if let TreeNode::Action { id, ty, parent} = node { - if let ActionType::SaveParams = ty { - self.emit_action_node(id, "SaveParams"); - self.emit_edge(parent, id); - } else { - unreachable!() - } - } else { - unreachable!() - } - } - - fn visit_emit_params(&mut self, node: &TreeNode) -> () { - if let TreeNode::Action { id, ty, parent} = node { - if let ActionType::EmitParams = ty { - self.emit_action_node(id, "EmitParams"); - self.emit_edge(parent, id); - } else { - unreachable!() - } - } else { - unreachable!() - } - } - fn visit_emit_body(&mut self, node: &TreeNode) -> () { if let TreeNode::Action { id, ty, parent} = node { if let ActionType::EmitBody = ty { diff --git a/src/generator/emitters.rs b/src/generator/emitters.rs index 33d0482e..4c5d8b1a 100644 --- a/src/generator/emitters.rs +++ b/src/generator/emitters.rs @@ -1043,6 +1043,7 @@ impl Emitter for WasmRewritingEmitter { }); } curr_loc.instr_created_args = arg_recs; + return true; } } false @@ -1067,6 +1068,7 @@ impl Emitter for WasmRewritingEmitter { exit(1); } } + return true; } } false diff --git a/src/generator/instr_generator.rs b/src/generator/instr_generator.rs index 3d1bf3ac..d2d38f5b 100644 --- a/src/generator/instr_generator.rs +++ b/src/generator/instr_generator.rs @@ -1,11 +1,10 @@ use log::{error, warn}; use crate::behavior::builder_visitor::SimpleAST; -use crate::behavior::tree::{ActionType, ActionWithChildType, BehaviorVisitor, DecoratorType, ParamActionType}; +use crate::behavior::tree::{ActionType, ActionWithChildType, ArgActionType, BehaviorVisitor, DecoratorType, ParamActionType}; use crate::behavior::tree::{BehaviorTree, Node}; use crate::generator::emitters::Emitter; use crate::generator::types::ExprFolder; use crate::parser::types::Probe; -use crate::verifier::types::ScopeType; /// The second phase of instrumenting a Wasm module by actually emitting the /// instrumentation code. @@ -40,6 +39,29 @@ impl InstrGenerator<'_, '_> { false } + fn set_context_info(&mut self, context: &String) { + // Set the current context info for probe lookup + self.context_name = context.clone(); + + let mut spec_split = context.split(":"); + if let Some(_whamm) = spec_split.next() { + if let Some(_whammy) = spec_split.next() { + if let Some(provider) = spec_split.next() { + self.curr_provider_name = provider.to_string(); + if let Some(package) = spec_split.next() { + self.curr_package_name = package.to_string(); + if let Some(event) = spec_split.next() { + self.curr_event_name = event.to_string(); + if let Some(probe) = spec_split.next() { + self.curr_probe_name = probe.to_string() + } + } + } + } + } + } + } + fn emit_cond(&mut self, cond: &usize) -> bool { let mut is_success = true; if let Some(node) = self.tree.get_node(cond.clone()) { @@ -128,28 +150,6 @@ impl BehaviorVisitor for InstrGenerator<'_, '_> { false } - fn visit_is_instr(&mut self, node: &Node) -> bool { - let mut is_success = true; - if let Node::Decorator {ty, child, ..} = node { - if let DecoratorType::IsInstr {instr_names} = ty { - if self.emitter.curr_instr_is_of_type(instr_names) { - // If the current instruction is of-interest, continue with the behavior tree logic - if let Some(node) = self.tree.get_node(child.clone()) { - is_success &= self.visit_node(node); - } - } else { - // If the decorator condition is false, return false - return false; - } - } else { - unreachable!() - } - } else { - unreachable!() - } - is_success - } - fn visit_is_probe_type(&mut self, node: &Node) -> bool { let mut is_success = true; if let Node::Decorator { ty, child, .. } = node { @@ -193,28 +193,6 @@ impl BehaviorVisitor for InstrGenerator<'_, '_> { is_success } - fn visit_has_params(&mut self, node: &Node) -> bool { - let mut is_success = true; - if let Node::Decorator { ty, child, .. } = node { - if let DecoratorType::HasParams = ty { - if self.emitter.has_params() { - // The current instruction has parameters, continue with behavior - if let Some(node) = self.tree.get_node(child.clone()) { - is_success &= self.visit_node(node); - } - } else { - // If the decorator condition is false, return false - return false; - } - } else { - unreachable!() - } - } else { - unreachable!() - } - is_success - } - fn visit_pred_is(&mut self, node: &Node) -> bool { if let Node::Decorator {ty, child, ..} = node { if let DecoratorType::PredIs{ val } = ty { @@ -240,30 +218,16 @@ impl BehaviorVisitor for InstrGenerator<'_, '_> { false } - fn visit_for_each_probe(&mut self, node: &Node) -> bool { + fn visit_save_params(&mut self, node: &Node) -> bool { let mut is_success = true; - // Assumption: before probes push/pop from stack so it is equivalent to what it was originally - // Assumption: after probes push/pop from stack so it is equivalent to what it was originally - - if let Node::Decorator { ty, child, .. } = node { - if let DecoratorType::ForEachProbe { target } = ty { - self.curr_probe_name = target.clone(); - - // Must pull the probe by index due to Rust calling constraints... - let probe_list_len = get_probes_from_ast(&self.ast, &self.curr_provider_name, &self.curr_package_name, - &self.curr_event_name, target).len(); - for i in Vec::from_iter(0..probe_list_len).iter() { - - if let Some(probe) = get_probe_at_idx(&self.ast, &self.curr_provider_name, &self.curr_package_name, - &self.curr_event_name, target, i) { - // make a clone of the current probe per instruction traversal - // this will reset the clone pred/body for each instruction! - self.curr_probe = Some(probe.clone()); - } - - if let Some(node) = self.tree.get_node(child.clone()) { - is_success &= self.visit_node(node); - } + if let Node::ArgAction {ty, force_success, ..} = node { + if let ArgActionType::SaveParams = ty { + if self.emitter.has_params() { + // The current instruction has parameters, save them + is_success &= self.emitter.save_params(); + } else { + // If no params, return whatever was configured to do + return force_success.clone(); } } else { unreachable!() @@ -274,25 +238,16 @@ impl BehaviorVisitor for InstrGenerator<'_, '_> { is_success } - fn visit_for_first_probe(&mut self, node: &Node) -> bool { + fn visit_emit_params(&mut self, node: &Node) -> bool { let mut is_success = true; - if let Node::Decorator {ty, child, .. } = node { - if let DecoratorType::ForFirstProbe { target } = ty { - let probe_list = get_probes_from_ast(&self.ast, &self.curr_provider_name, &self.curr_package_name, - &self.curr_event_name, target); - if probe_list.len() > 1 { - warn!("There is more than one probe for probe type '{}'. So only emitting first probe, ignoring rest.", target) - } - self.curr_probe_name = target.clone(); - // make a clone of the first probe per instruction traversal - // this will reset the clone pred/body for each instruction! - if let Some(probe) = probe_list.get(0) { - self.curr_probe = Some(probe.clone()); - } - - // Process the instructions for this single probe! - if let Some(node) = self.tree.get_node(child.clone()) { - is_success &= self.visit_node(node); + if let Node::ArgAction { ty, force_success, ..} = node { + if let ArgActionType::EmitParams = ty { + if self.emitter.has_params() { + // The current instruction has parameters, emit them + is_success &= self.emitter.emit_params(); + } else { + // If no params, return whatever was configured to do + return force_success.clone(); } } else { unreachable!() @@ -306,29 +261,122 @@ impl BehaviorVisitor for InstrGenerator<'_, '_> { fn visit_enter_package(&mut self, node: &Node) -> bool { let mut is_success = true; if let Node::ActionWithChild { ty, child, .. } = node { - let ActionWithChildType::EnterPackage { package_name } = ty; - if package_name == "bytecode" { - // Process first instruction! - if let Some(node) = self.tree.get_node(child.clone()) { - is_success &= self.visit_node(node); + if let ActionWithChildType::EnterPackage { context, package_name, events } = ty { + if package_name == "bytecode" { + // Perform 'bytecode' package logic + is_success &= self.emitter.enter_named_scope(package_name); + if is_success { + self.set_context_info(context); + } + + let mut first_instr = true; + while first_instr || self.emitter.has_next_instr() { + if !first_instr { + self.emitter.next_instr(); + } + + let instr_ty = self.emitter.curr_instr_type(); + // is this an instruction of-interest? + if let Some(globals) = events.get(&instr_ty) { + // enter this event's scope + self.emitter.enter_named_scope(&instr_ty); + self.curr_event_name = instr_ty.clone(); + + // define this instruction type's compiler variables + for global in globals { + is_success &= self.emitter.define_compiler_var(&self.context_name, global); + } + + // continue with logic + if let Some(node) = self.tree.get_node(child.clone()) { + is_success &= self.visit_node(node); + } + + // exit this event's scope + self.emitter.exit_scope(); + } + first_instr = false; + } + + self.emitter.exit_scope(); + } + } + } else { + unreachable!() + } + is_success + } + + fn visit_enter_probe(&mut self, node: &Node) -> bool { + let mut is_success = true; + if let Node::ActionWithChild { ty, child, .. } = node { + if let ActionWithChildType::EnterProbe { probe_name, global_names, .. } = ty { + // enter probe's scope + is_success &= self.emitter.enter_named_scope(probe_name); + if is_success { + self.curr_probe_name = probe_name.clone(); + } + // define this probe's compiler variables + for global in global_names { + is_success &= self.emitter.define_compiler_var(&self.context_name, global); } + if probe_name == "before" || probe_name == "after" { + // Perform 'before' and 'after' probe logic + // Must pull the probe by index due to Rust calling constraints... + let probe_list_len = get_probes_from_ast(&self.ast, &self.curr_provider_name, &self.curr_package_name, + &self.curr_event_name, probe_name).len(); + for i in Vec::from_iter(0..probe_list_len).iter() { + + if let Some(probe) = get_probe_at_idx(&self.ast, &self.curr_provider_name, &self.curr_package_name, + &self.curr_event_name, probe_name, i) { + // make a clone of the current probe per instruction traversal + // this will reset the clone pred/body for each instruction! + let mut probe_cloned = probe.clone(); + if let Some(pred) = &mut probe_cloned.predicate { + // Fold predicate + is_success &= self.emitter.fold_expr(pred); + } + self.curr_probe = Some(probe_cloned); + } - // Process the rest of the instructions - while self.emitter.has_next_instr() { - self.emitter.next_instr(); + // Process the instructions for this probe! + if let Some(node) = self.tree.get_node(child.clone()) { + is_success &= self.visit_node(node); + } + } + } else if probe_name == "alt" { + // Perform 'alt' probe logic + let probe_list = get_probes_from_ast(&self.ast, &self.curr_provider_name, &self.curr_package_name, + &self.curr_event_name, probe_name); + if probe_list.len() > 1 { + warn!("There is more than one probe for probe type '{}'. So only emitting first probe, ignoring rest.", probe_name) + } + // make a clone of the first probe per instruction traversal + // this will reset the clone pred/body for each instruction! + if let Some(probe) = probe_list.get(0) { + let mut probe_cloned = probe.clone(); + if let Some(pred) = &mut probe_cloned.predicate { + // Fold predicate + is_success &= self.emitter.fold_expr(pred); + } + self.curr_probe = Some(probe_cloned); + } + + // Process the instructions for this single probe! if let Some(node) = self.tree.get_node(child.clone()) { is_success &= self.visit_node(node); } + } else { + unreachable!() } + self.emitter.exit_scope(); } - } else { - unreachable!() } is_success } fn visit_emit_if_else(&mut self, node: &Node) -> bool { - if let Node::ParameterizedAction {ty, .. } = node { + if let Node::ActionWithParams {ty, .. } = node { if let ParamActionType::EmitIfElse { cond, conseq, alt } = ty { self.emitter.emit_if_else(); self.emit_cond(cond); @@ -345,7 +393,7 @@ impl BehaviorVisitor for InstrGenerator<'_, '_> { } fn visit_emit_if(&mut self, node: &Node) -> bool { - if let Node::ParameterizedAction { ty, .. } = node { + if let Node::ActionWithParams { ty, .. } = node { if let ParamActionType::EmitIf { cond, conseq } = ty { self.emitter.emit_if(); self.emit_cond(cond); @@ -366,63 +414,7 @@ impl BehaviorVisitor for InstrGenerator<'_, '_> { if let ActionType::EnterScope{ context, scope_name } = ty { is_success &= self.emitter.enter_named_scope(scope_name); if is_success { - // Set the current context info for probe lookup - self.context_name = context.clone(); - - let mut spec_split = context.split(":"); - if let Some(_whamm) = spec_split.next() { - if let Some(_whammy) = spec_split.next() { - if let Some(provider) = spec_split.next() { - self.curr_provider_name = provider.to_string(); - if let Some(package) = spec_split.next() { - self.curr_package_name = package.to_string(); - if let Some(event) = spec_split.next() { - self.curr_event_name = event.to_string(); - if let Some(probe) = spec_split.next() { - self.curr_probe_name = probe.to_string() - } - } - } - } - } - } - } - } else { - unreachable!() - } - } else { - unreachable!() - } - is_success - } - - fn visit_enter_scope_of(&mut self, node: &Node) -> bool { - let mut is_success = true; - if let Node::Action { ty, ..} = node { - if let ActionType::EnterScopeOf { context, scope_ty } = ty { - match scope_ty { - ScopeType::Event => { - let instr_name = self.emitter.curr_instr_type(); - is_success &= self.emitter.enter_named_scope(&instr_name); - if is_success { - // Set the current context info for probe lookup - self.context_name = context.clone(); - - let mut spec_split = context.split(":"); - if let Some(_whamm) = spec_split.next() { - if let Some(_whammy) = spec_split.next() { - if let Some(provider) = spec_split.next() { - self.curr_provider_name = provider.to_string(); - if let Some(package) = spec_split.next() { - self.curr_package_name = package.to_string(); - self.curr_event_name = instr_name; - } - } - } - } - } - } - _ => unimplemented!() + self.set_context_info(context); } } else { unreachable!() @@ -479,24 +471,6 @@ impl BehaviorVisitor for InstrGenerator<'_, '_> { is_success } - fn visit_fold_pred(&mut self, node: &Node) -> bool { - let mut is_success = true; - if let Node::Action { ty, ..} = node { - if let ActionType::FoldPred = ty { - if let Some(probe) = &mut self.curr_probe { - if let Some(pred) = &mut probe.predicate { - is_success &= self.emitter.fold_expr(pred); - } - } - } else { - unreachable!() - } - } else { - unreachable!() - } - is_success - } - fn visit_reset(&mut self, node: &Node) -> bool { let is_success = true; if let Node::Action {ty, ..} = node { @@ -511,34 +485,6 @@ impl BehaviorVisitor for InstrGenerator<'_, '_> { is_success } - fn visit_save_params(&mut self, node: &Node) -> bool { - let mut is_success = true; - if let Node::Action {ty, ..} = node { - if let ActionType::SaveParams = ty { - is_success &= self.emitter.save_params(); - } else { - unreachable!() - } - } else { - unreachable!() - } - is_success - } - - fn visit_emit_params(&mut self, node: &Node) -> bool { - let mut is_success = true; - if let Node::Action { ty, ..} = node { - if let ActionType::EmitParams = ty { - is_success &= self.emitter.emit_params(); - } else { - unreachable!() - } - } else { - unreachable!() - } - is_success - } - fn visit_emit_body(&mut self, node: &Node) -> bool { let mut is_success = true; if let Node::Action {ty, ..} = node {