git.delta.rocks / jrsonnet / refs/commits / 5c0b9a1be089

difftreelog

perf build stacktrace only on unwind

Лач2020-07-02parent: #74729ec.patch.diff
in: master

2 files changed

modifiedcrates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate.rs
@@ -658,9 +658,11 @@
 		Num(v) => Val::new_checked_num(*v)?,
 		BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, &v1, *o, &v2)?,
 		UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,
-		Var(name) => push(loc, "var", || {
-			Ok(Val::Lazy(context.binding(name.clone())?).unwrap_if_lazy()?)
-		})?,
+		Var(name) => push(
+			loc,
+			|| "var".to_owned(),
+			|| Ok(Val::Lazy(context.binding(name.clone())?).unwrap_if_lazy()?),
+		)?,
 		Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => {
 			let name = evaluate(context.clone(), index)?.try_cast_str("object index")?;
 			context
@@ -769,10 +771,14 @@
 		Apply(value, args, tailstrict) => evaluate_apply(context, value, args, loc, *tailstrict)?,
 		Function(params, body) => evaluate_method(context, params.clone(), body.clone()),
 		AssertExpr(AssertStmt(value, msg), returned) => {
-			let assertion_result = push(&value.1, "assertion condition", || {
-				evaluate(context.clone(), &value)?
-					.try_cast_bool("assertion condition should be boolean")
-			})?;
+			let assertion_result = push(
+				&value.1,
+				|| "assertion condition".to_owned(),
+				|| {
+					evaluate(context.clone(), &value)?
+						.try_cast_bool("assertion condition should be boolean")
+				},
+			)?;
 			if assertion_result {
 				evaluate(context, returned)?
 			} else if let Some(msg) = msg {
@@ -781,9 +787,15 @@
 				create_error_result(crate::Error::AssertionFailed(Val::Null))?
 			}
 		}
-		Error(e) => create_error_result(crate::Error::RuntimeError(
-			evaluate(context, e)?.try_cast_str("error text should be string")?,
-		))?,
+		Error(e) => push(
+			&loc,
+			|| "error statement".to_owned(),
+			|| {
+				create_error_result(crate::Error::RuntimeError(
+					evaluate(context, e)?.try_cast_str("error text should be string")?,
+				))?
+			},
+		)?,
 		IfElse {
 			cond,
 			cond_then,
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
7272
73#[derive(Default)]73#[derive(Default)]
74struct EvaluationData {74struct EvaluationData {
75 /// Used for stack-overflows and stacktraces75 /// Used for stack overflow detection, stacktrace is now populated on unwind
76 stack: Vec<StackTraceElement>,76 stack_depth: usize,
77 /// Contains file source codes and evaluated results for imports and pretty77 /// Contains file source codes and evaluated results for imports and pretty
78 /// printing stacktraces78 /// printing stacktraces
79 files: HashMap<Rc<PathBuf>, FileData>,79 files: HashMap<Rc<PathBuf>, FileData>,
103}103}
104pub(crate) fn push<T>(104pub(crate) fn push<T>(
105 e: &Option<ExprLocation>,105 e: &Option<ExprLocation>,
106 comment: &str,106 frame_desc: impl FnOnce() -> String,
107 f: impl FnOnce() -> Result<T>,107 f: impl FnOnce() -> Result<T>,
108) -> Result<T> {108) -> Result<T> {
109 if e.is_some() {109 if let Some(v) = e {
110 with_state(|s| s.push(e.clone().unwrap(), comment.to_owned(), f))110 with_state(|s| s.push(&v, frame_desc, f))
111 } else {111 } else {
112 f()112 f()
113 }113 }
332 /// Executes code, creating new stack frame332 /// Executes code, creating new stack frame
333 pub fn push<T>(333 pub fn push<T>(
334 &self,334 &self,
335 e: ExprLocation,335 e: &ExprLocation,
336 comment: String,336 frame_desc: impl FnOnce() -> String,
337 f: impl FnOnce() -> Result<T>,337 f: impl FnOnce() -> Result<T>,
338 ) -> Result<T> {338 ) -> Result<T> {
339 {339 {
340 let mut data = self.data_mut();340 let mut data = self.data_mut();
341 let stack = &mut data.stack;341 let stack_depth = &mut data.stack_depth;
342 if stack.len() > self.settings().max_stack_frames {342 if *stack_depth > self.settings().max_stack_frames {
343 // Error creation uses data, so i drop guard here343 // Error creation uses data, so i drop guard here
344 drop(data);344 drop(data);
345 return Err(self.error(Error::StackOverflow));345 return Err(self.error(Error::StackOverflow));
346 } else {346 } else {
347 stack.push(StackTraceElement(e, comment));347 *stack_depth+=1;
348 }348 }
349 }349 }
350 let result = f();350 let result = f();
351 self.data_mut().stack.pop();351 self.data_mut().stack_depth -= 1;
352 if let Err(mut err) = result {
353 (err.1).0.push(StackTraceElement(e.clone(), frame_desc()));
354 return Err(err);
355 }
352 result356 result
353 }357 }
354
355 /// Returns current stack trace
356 pub fn stack_trace(&self) -> StackTrace {
357 StackTrace(
358 self.data()
359 .stack
360 .iter()
361 .rev()
362 .take(self.settings().max_stack_trace_size)
363 .cloned()
364 .collect(),
365 )
366 }
367358
368 /// Creates error with stack trace359 /// Creates error with stack trace
369 pub fn error(&self, err: Error) -> LocError {360 pub fn error(&self, err: Error) -> LocError {
370 LocError(err, self.stack_trace())361 LocError(err, StackTrace(vec![]))
371 }362 }
372363
373 /// Runs passed function in state (required, if function needs to modify stack trace)364 /// Runs passed function in state (required, if function needs to modify stack trace)
396 #[test]387 #[test]
397 fn eval_state_stacktrace() {388 fn eval_state_stacktrace() {
398 let state = EvaluationState::default();389 let state = EvaluationState::default();
390 state.run_in_state(||{
399 state391 state
400 .push(392 .push(
401 ExprLocation(Rc::new(PathBuf::from("test1.jsonnet")), 10, 20),393 &ExprLocation(Rc::new(PathBuf::from("test1.jsonnet")), 10, 20),
402 "outer".to_owned(),394 || "outer".to_owned(),
403 || {395 || {
404 state.push(396 state.push(
405 ExprLocation(Rc::new(PathBuf::from("test2.jsonnet")), 30, 40),397 &ExprLocation(Rc::new(PathBuf::from("test2.jsonnet")), 30, 40),
406 "inner".to_owned(),398 || "inner".to_owned(),
407 || {399 || {
408 Ok(())400 Err(create_error(crate::error::Error::RuntimeError("".into())))
409 },401 },
410 )?;402 )?;
411 Ok(())403 Ok(())
412 },404 },
413 )405 )
406 .unwrap();
414 .unwrap();407 });
415 }408 }
416409
417 #[test]410 #[test]