difftreelog
perf(evaluator) remove inline attribute
in: master
6 files changed
crates/jsonnet-evaluator/Cargo.tomldiffbeforeafterboth--- a/crates/jsonnet-evaluator/Cargo.toml
+++ b/crates/jsonnet-evaluator/Cargo.toml
@@ -10,6 +10,7 @@
default = ["serialized-stdlib", "faster"]
serialized-stdlib = ["serde", "bincode"]
# Replace some standard library functions with faster implementations
+# Library works fine without this feature, but requires more memory and time for std function calls
faster = []
[dependencies]
crates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/evaluate.rs
+++ b/crates/jsonnet-evaluator/src/evaluate.rs
@@ -168,7 +168,6 @@
future_wrapper!(HashMap<String, LazyBinding>, FutureNewBindings);
future_wrapper!(ObjValue, FutureObjValue);
-#[inline(always)]
pub fn evaluate_comp<T>(
context: Context,
value: &impl Fn(Context) -> Result<T>,
@@ -370,7 +369,6 @@
})
}
-#[inline(always)]
pub fn evaluate(context: Context, expr: &LocExpr) -> Result<Val> {
use Expr::*;
let locexpr = expr.clone();
@@ -731,8 +729,7 @@
(ns, name) => panic!("Intristic not found: {}.{}", ns, name),
},
Val::Func(f) => {
- let body = #[inline(always)]
- || f.evaluate(context, args, *tailstrict);
+ let body = || f.evaluate(context, args, *tailstrict);
if *tailstrict {
body()?
} else {
crates/jsonnet-evaluator/src/function.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/function.rs
+++ b/crates/jsonnet-evaluator/src/function.rs
@@ -24,7 +24,6 @@
///
/// ## Notes
/// This function is always inlined for tailstrict
-#[inline(always)]
pub(crate) fn inline_parse_function_call(
ctx: Context,
body_ctx: Option<Context>,
@@ -79,7 +78,6 @@
Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None)?)
}
-#[inline(always)]
pub(crate) fn place_args(
ctx: Context,
body_ctx: Option<Context>,
crates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/lib.rs
+++ b/crates/jsonnet-evaluator/src/lib.rs
@@ -2,7 +2,6 @@
#![feature(type_alias_impl_trait)]
#![feature(debug_non_exhaustive)]
#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]
-#![feature(stmt_expr_attributes)]
mod ctx;
mod dynamic;
mod error;
@@ -81,17 +80,14 @@
/// Global state is fine there
pub(crate) static EVAL_STATE: RefCell<Option<EvaluationState>> = RefCell::new(None)
}
-#[inline(always)]
pub(crate) fn with_state<T>(f: impl FnOnce(&EvaluationState) -> T) -> T {
EVAL_STATE.with(
- #[inline(always)]
|s| f(s.borrow().as_ref().unwrap()),
)
}
pub(crate) fn create_error<T>(err: Error) -> Result<T> {
with_state(|s| s.error(err))
}
-#[inline(always)]
pub(crate) fn push<T>(e: LocExpr, comment: String, f: impl FnOnce() -> Result<T>) -> Result<T> {
with_state(|s| s.push(e, comment, f))
}
@@ -251,7 +247,6 @@
Context::new().extend_unbound(new_bindings, None, None, None)
}
- #[inline(always)]
pub fn push<T>(&self, e: LocExpr, comment: String, f: impl FnOnce() -> Result<T>) -> Result<T> {
{
let mut stack = self.0.stack.borrow_mut();
@@ -287,7 +282,6 @@
Err(LocError(err, self.stack_trace()))
}
- #[inline(always)]
fn run_in_state<T>(&self, f: impl FnOnce() -> T) -> T {
EVAL_STATE.with(|v| {
let has_state = v.borrow().is_some();
crates/jsonnet-evaluator/src/map.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/map.rs
+++ b/crates/jsonnet-evaluator/src/map.rs
@@ -18,7 +18,6 @@
}))
}
- #[inline(always)]
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q>,
crates/jsonnet-evaluator/src/val.rsdiffbeforeafterboth1use crate::{2 create_error, evaluate,3 function::{inline_parse_function_call, place_args},4 with_state, Context, Error, ObjValue, Result,5};6use jsonnet_parser::{el, Arg, ArgsDesc, Expr, LocExpr, ParamsDesc};7use std::{8 cell::RefCell,9 fmt::{Debug, Display},10 rc::Rc,11};1213struct LazyValInternals {14 pub f: Option<Box<dyn Fn() -> Result<Val>>>,15 pub cached: RefCell<Option<Val>>,16}17#[derive(Clone)]18pub struct LazyVal(Rc<LazyValInternals>);19impl LazyVal {20 pub fn new(f: Box<dyn Fn() -> Result<Val>>) -> Self {21 LazyVal(Rc::new(LazyValInternals {22 f: Some(f),23 cached: RefCell::new(None),24 }))25 }26 pub fn new_resolved(val: Val) -> Self {27 LazyVal(Rc::new(LazyValInternals {28 f: None,29 cached: RefCell::new(Some(val)),30 }))31 }32 pub fn evaluate(&self) -> Result<Val> {33 {34 let cached = self.0.cached.borrow();35 if cached.is_some() {36 return Ok(cached.clone().unwrap());37 }38 }39 let result = (self.0.f.as_ref().unwrap())()?;40 self.0.cached.borrow_mut().replace(result.clone());41 Ok(result)42 }43}4445#[macro_export]46macro_rules! lazy_val {47 ($f: expr) => {48 $crate::LazyVal::new(Box::new($f))49 };50}51#[macro_export]52macro_rules! resolved_lazy_val {53 ($f: expr) => {54 $crate::LazyVal::new_resolved($f)55 };56}57impl Debug for LazyVal {58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {59 if self.0.cached.borrow().is_some() {60 write!(f, "{:?}", self.0.cached.borrow().clone().unwrap())61 } else {62 write!(f, "Lazy")63 }64 }65}66impl PartialEq for LazyVal {67 fn eq(&self, other: &Self) -> bool {68 Rc::ptr_eq(&self.0, &other.0)69 }70}7172#[derive(Debug, PartialEq, Clone)]73pub struct FuncDesc {74 pub ctx: Context,75 pub params: ParamsDesc,76 pub body: LocExpr,77}78impl FuncDesc {79 /// This function is always inlined to make tailstrict work80 #[inline(always)]81 pub fn evaluate(&self, call_ctx: Context, args: &ArgsDesc, tailstrict: bool) -> Result<Val> {82 let ctx = inline_parse_function_call(83 call_ctx,84 Some(self.ctx.clone()),85 &self.params,86 args,87 tailstrict,88 )?;89 evaluate(ctx, &self.body)90 }9192 #[inline(always)]93 pub fn evaluate_values(&self, call_ctx: Context, args: &[Val]) -> Result<Val> {94 let ctx = place_args(call_ctx, Some(self.ctx.clone()), &self.params, args)?;95 evaluate(ctx, &self.body)96 }97}9899#[derive(Debug, Clone)]100pub enum ValType {101 Bool,102 Null,103 Str,104 Num,105 Arr,106 Obj,107 Func,108}109impl ValType {110 pub fn name(&self) -> &'static str {111 use ValType::*;112 match self {113 Bool => "boolean",114 Null => "null",115 Str => "string",116 Num => "number",117 Arr => "array",118 Obj => "object",119 Func => "function",120 }121 }122}123impl Display for ValType {124 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {125 write!(f, "{}", self.name())126 }127}128129#[derive(Debug, PartialEq, Clone)]130pub enum Val {131 Bool(bool),132 Null,133 Str(String),134 Num(f64),135 Lazy(LazyVal),136 Arr(Vec<Val>),137 Obj(ObjValue),138 Func(FuncDesc),139140 // Library functions implemented in native141 Intristic(String, String),142}143impl Val {144 pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {145 match self.unwrap_if_lazy()? {146 Val::Bool(v) => Ok(v),147 v => create_error(Error::TypeMismatch(148 context,149 vec![ValType::Bool],150 v.value_type()?,151 )),152 }153 }154 pub fn try_cast_str(self, context: &'static str) -> Result<String> {155 match self.unwrap_if_lazy()? {156 Val::Str(v) => Ok(v),157 v => create_error(Error::TypeMismatch(158 context,159 vec![ValType::Str],160 v.value_type()?,161 )),162 }163 }164 pub fn unwrap_if_lazy(self) -> Result<Self> {165 Ok(if let Val::Lazy(v) = self {166 v.evaluate()?.unwrap_if_lazy()?167 } else {168 self169 })170 }171 pub fn value_type(&self) -> Result<ValType> {172 Ok(match self {173 Val::Str(..) => ValType::Str,174 Val::Num(..) => ValType::Num,175 Val::Arr(..) => ValType::Arr,176 Val::Obj(..) => ValType::Obj,177 Val::Func(..) => ValType::Func,178 Val::Bool(_) => ValType::Bool,179 Val::Null => ValType::Null,180 Val::Intristic(_, _) => ValType::Func,181 Val::Lazy(_) => self.clone().unwrap_if_lazy()?.value_type()?,182 })183 }184 pub fn into_json(self, padding: usize) -> Result<String> {185 with_state(|s| {186 let ctx = s187 .create_default_context()?188 .with_var("__tmp__to_json__".to_owned(), self)?;189 if let Val::Str(result) = evaluate(190 ctx,191 &el!(Expr::Apply(192 el!(Expr::Index(193 el!(Expr::Var("std".to_owned())),194 el!(Expr::Str("manifestJsonEx".to_owned()))195 )),196 ArgsDesc(vec![197 Arg(None, el!(Expr::Var("__tmp__to_json__".to_owned()))),198 Arg(None, el!(Expr::Str(" ".repeat(padding))))199 ]),200 false201 )),202 )? {203 Ok(result)204 } else {205 unreachable!()206 }207 })208 }209}1use crate::{2 create_error, evaluate,3 function::{inline_parse_function_call, place_args},4 with_state, Context, Error, ObjValue, Result,5};6use jsonnet_parser::{el, Arg, ArgsDesc, Expr, LocExpr, ParamsDesc};7use std::{8 cell::RefCell,9 fmt::{Debug, Display},10 rc::Rc,11};1213struct LazyValInternals {14 pub f: Option<Box<dyn Fn() -> Result<Val>>>,15 pub cached: RefCell<Option<Val>>,16}17#[derive(Clone)]18pub struct LazyVal(Rc<LazyValInternals>);19impl LazyVal {20 pub fn new(f: Box<dyn Fn() -> Result<Val>>) -> Self {21 LazyVal(Rc::new(LazyValInternals {22 f: Some(f),23 cached: RefCell::new(None),24 }))25 }26 pub fn new_resolved(val: Val) -> Self {27 LazyVal(Rc::new(LazyValInternals {28 f: None,29 cached: RefCell::new(Some(val)),30 }))31 }32 pub fn evaluate(&self) -> Result<Val> {33 {34 let cached = self.0.cached.borrow();35 if cached.is_some() {36 return Ok(cached.clone().unwrap());37 }38 }39 let result = (self.0.f.as_ref().unwrap())()?;40 self.0.cached.borrow_mut().replace(result.clone());41 Ok(result)42 }43}4445#[macro_export]46macro_rules! lazy_val {47 ($f: expr) => {48 $crate::LazyVal::new(Box::new($f))49 };50}51#[macro_export]52macro_rules! resolved_lazy_val {53 ($f: expr) => {54 $crate::LazyVal::new_resolved($f)55 };56}57impl Debug for LazyVal {58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {59 if self.0.cached.borrow().is_some() {60 write!(f, "{:?}", self.0.cached.borrow().clone().unwrap())61 } else {62 write!(f, "Lazy")63 }64 }65}66impl PartialEq for LazyVal {67 fn eq(&self, other: &Self) -> bool {68 Rc::ptr_eq(&self.0, &other.0)69 }70}7172#[derive(Debug, PartialEq, Clone)]73pub struct FuncDesc {74 pub ctx: Context,75 pub params: ParamsDesc,76 pub body: LocExpr,77}78impl FuncDesc {79 /// This function is always inlined to make tailstrict work80 pub fn evaluate(&self, call_ctx: Context, args: &ArgsDesc, tailstrict: bool) -> Result<Val> {81 let ctx = inline_parse_function_call(82 call_ctx,83 Some(self.ctx.clone()),84 &self.params,85 args,86 tailstrict,87 )?;88 evaluate(ctx, &self.body)89 }9091 pub fn evaluate_values(&self, call_ctx: Context, args: &[Val]) -> Result<Val> {92 let ctx = place_args(call_ctx, Some(self.ctx.clone()), &self.params, args)?;93 evaluate(ctx, &self.body)94 }95}9697#[derive(Debug, Clone)]98pub enum ValType {99 Bool,100 Null,101 Str,102 Num,103 Arr,104 Obj,105 Func,106}107impl ValType {108 pub fn name(&self) -> &'static str {109 use ValType::*;110 match self {111 Bool => "boolean",112 Null => "null",113 Str => "string",114 Num => "number",115 Arr => "array",116 Obj => "object",117 Func => "function",118 }119 }120}121impl Display for ValType {122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {123 write!(f, "{}", self.name())124 }125}126127#[derive(Debug, PartialEq, Clone)]128pub enum Val {129 Bool(bool),130 Null,131 Str(String),132 Num(f64),133 Lazy(LazyVal),134 Arr(Vec<Val>),135 Obj(ObjValue),136 Func(FuncDesc),137138 // Library functions implemented in native139 Intristic(String, String),140}141impl Val {142 pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {143 match self.unwrap_if_lazy()? {144 Val::Bool(v) => Ok(v),145 v => create_error(Error::TypeMismatch(146 context,147 vec![ValType::Bool],148 v.value_type()?,149 )),150 }151 }152 pub fn try_cast_str(self, context: &'static str) -> Result<String> {153 match self.unwrap_if_lazy()? {154 Val::Str(v) => Ok(v),155 v => create_error(Error::TypeMismatch(156 context,157 vec![ValType::Str],158 v.value_type()?,159 )),160 }161 }162 pub fn unwrap_if_lazy(self) -> Result<Self> {163 Ok(if let Val::Lazy(v) = self {164 v.evaluate()?.unwrap_if_lazy()?165 } else {166 self167 })168 }169 pub fn value_type(&self) -> Result<ValType> {170 Ok(match self {171 Val::Str(..) => ValType::Str,172 Val::Num(..) => ValType::Num,173 Val::Arr(..) => ValType::Arr,174 Val::Obj(..) => ValType::Obj,175 Val::Func(..) => ValType::Func,176 Val::Bool(_) => ValType::Bool,177 Val::Null => ValType::Null,178 Val::Intristic(_, _) => ValType::Func,179 Val::Lazy(_) => self.clone().unwrap_if_lazy()?.value_type()?,180 })181 }182 pub fn into_json(self, padding: usize) -> Result<String> {183 with_state(|s| {184 let ctx = s185 .create_default_context()?186 .with_var("__tmp__to_json__".to_owned(), self)?;187 if let Val::Str(result) = evaluate(188 ctx,189 &el!(Expr::Apply(190 el!(Expr::Index(191 el!(Expr::Var("std".to_owned())),192 el!(Expr::Str("manifestJsonEx".to_owned()))193 )),194 ArgsDesc(vec![195 Arg(None, el!(Expr::Var("__tmp__to_json__".to_owned()))),196 Arg(None, el!(Expr::Str(" ".repeat(padding))))197 ]),198 false199 )),200 )? {201 Ok(result)202 } else {203 unreachable!()204 }205 })206 }207}