difftreelog
perf build stacktrace only on unwind
in: master
2 files changed
crates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth658 Num(v) => Val::new_checked_num(*v)?,658 Num(v) => Val::new_checked_num(*v)?,659 BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, &v1, *o, &v2)?,659 BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, &v1, *o, &v2)?,660 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,660 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,661 Var(name) => push(loc, "var", || {661 Var(name) => push(662 loc,663 || "var".to_owned(),662 Ok(Val::Lazy(context.binding(name.clone())?).unwrap_if_lazy()?)664 || Ok(Val::Lazy(context.binding(name.clone())?).unwrap_if_lazy()?),663 })?,665 )?,664 Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => {666 Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => {665 let name = evaluate(context.clone(), index)?.try_cast_str("object index")?;667 let name = evaluate(context.clone(), index)?.try_cast_str("object index")?;666 context668 context771 AssertExpr(AssertStmt(value, msg), returned) => {773 AssertExpr(AssertStmt(value, msg), returned) => {772 let assertion_result = push(&value.1, "assertion condition", || {774 let assertion_result = push(775 &value.1,776 || "assertion condition".to_owned(),777 || {773 evaluate(context.clone(), &value)?778 evaluate(context.clone(), &value)?774 .try_cast_bool("assertion condition should be boolean")779 .try_cast_bool("assertion condition should be boolean")775 })?;780 },781 )?;776 if assertion_result {782 if assertion_result {777 evaluate(context, returned)?783 evaluate(context, returned)?781 create_error_result(crate::Error::AssertionFailed(Val::Null))?787 create_error_result(crate::Error::AssertionFailed(Val::Null))?782 }788 }783 }789 }784 Error(e) => create_error_result(crate::Error::RuntimeError(790 Error(e) => push(791 &loc,792 || "error statement".to_owned(),793 || {794 create_error_result(crate::Error::RuntimeError(785 evaluate(context, e)?.try_cast_str("error text should be string")?,795 evaluate(context, e)?.try_cast_str("error text should be string")?,786 ))?,796 ))?797 },798 )?,787 IfElse {799 IfElse {788 cond,800 cond,789 cond_then,801 cond_then,crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -72,8 +72,8 @@
#[derive(Default)]
struct EvaluationData {
- /// Used for stack-overflows and stacktraces
- stack: Vec<StackTraceElement>,
+ /// Used for stack overflow detection, stacktrace is now populated on unwind
+ stack_depth: usize,
/// Contains file source codes and evaluated results for imports and pretty
/// printing stacktraces
files: HashMap<Rc<PathBuf>, FileData>,
@@ -103,11 +103,11 @@
}
pub(crate) fn push<T>(
e: &Option<ExprLocation>,
- comment: &str,
+ frame_desc: impl FnOnce() -> String,
f: impl FnOnce() -> Result<T>,
) -> Result<T> {
- if e.is_some() {
- with_state(|s| s.push(e.clone().unwrap(), comment.to_owned(), f))
+ if let Some(v) = e {
+ with_state(|s| s.push(&v, frame_desc, f))
} else {
f()
}
@@ -332,42 +332,33 @@
/// Executes code, creating new stack frame
pub fn push<T>(
&self,
- e: ExprLocation,
- comment: String,
+ e: &ExprLocation,
+ frame_desc: impl FnOnce() -> String,
f: impl FnOnce() -> Result<T>,
) -> Result<T> {
{
let mut data = self.data_mut();
- let stack = &mut data.stack;
- if stack.len() > self.settings().max_stack_frames {
+ let stack_depth = &mut data.stack_depth;
+ if *stack_depth > self.settings().max_stack_frames {
// Error creation uses data, so i drop guard here
drop(data);
return Err(self.error(Error::StackOverflow));
} else {
- stack.push(StackTraceElement(e, comment));
+ *stack_depth+=1;
}
}
let result = f();
- self.data_mut().stack.pop();
+ self.data_mut().stack_depth -= 1;
+ if let Err(mut err) = result {
+ (err.1).0.push(StackTraceElement(e.clone(), frame_desc()));
+ return Err(err);
+ }
result
}
- /// Returns current stack trace
- pub fn stack_trace(&self) -> StackTrace {
- StackTrace(
- self.data()
- .stack
- .iter()
- .rev()
- .take(self.settings().max_stack_trace_size)
- .cloned()
- .collect(),
- )
- }
-
/// Creates error with stack trace
pub fn error(&self, err: Error) -> LocError {
- LocError(err, self.stack_trace())
+ LocError(err, StackTrace(vec![]))
}
/// Runs passed function in state (required, if function needs to modify stack trace)
@@ -396,22 +387,24 @@
#[test]
fn eval_state_stacktrace() {
let state = EvaluationState::default();
- state
+ state.run_in_state(||{
+ state
.push(
- ExprLocation(Rc::new(PathBuf::from("test1.jsonnet")), 10, 20),
- "outer".to_owned(),
+ &ExprLocation(Rc::new(PathBuf::from("test1.jsonnet")), 10, 20),
+ || "outer".to_owned(),
|| {
state.push(
- ExprLocation(Rc::new(PathBuf::from("test2.jsonnet")), 30, 40),
- "inner".to_owned(),
+ &ExprLocation(Rc::new(PathBuf::from("test2.jsonnet")), 30, 40),
+ || "inner".to_owned(),
|| {
- Ok(())
+ Err(create_error(crate::error::Error::RuntimeError("".into())))
},
)?;
Ok(())
},
)
.unwrap();
+ });
}
#[test]