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
658 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 context
771 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,
modifiedcrates/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]