From 2b28b1c83d8f48a6e3e179223a125e8372ae71f5 Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Mon, 28 Sep 2026 14:57:19 -0700 Subject: [PATCH] Split ExecutionFrame::Next() into a fast path and an out-of-line slow path. `Next()` is called once per evaluation step. It is split into a small fast path and an out-of-line `ReturnFromSubexpression()`. The fast path returns the next step in the current execution path, or `nullptr` when the top-level program finishes (which happens once per evaluation). The rare case of returning from a lazily evaluated subexpression is handled out of line. This keeps `Next()` small enough to inline into the `ExecutionFrame::Evaluate` loop without changing behavior. PiperOrigin-RevId: 989862082 --- eval/eval/evaluator_core.cc | 18 ++++++++++++++++++ eval/eval/evaluator_core.h | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/eval/eval/evaluator_core.cc b/eval/eval/evaluator_core.cc index 0aa6000a4..458a56d0b 100644 --- a/eval/eval/evaluator_core.cc +++ b/eval/eval/evaluator_core.cc @@ -17,6 +17,7 @@ #include #include +#include "absl/base/attributes.h" #include "absl/base/nullability.h" #include "absl/base/optimization.h" #include "absl/log/absl_check.h" @@ -39,6 +40,23 @@ void FlatExpressionEvaluatorState::Reset() { } const ExpressionStep* ExecutionFrame::Next() { + if (ABSL_PREDICT_TRUE(pc_ < execution_path_.size())) { + const ExpressionStep* step = &execution_path_[pc_++]; + ABSL_ASSUME(step != nullptr); + return step; + } + // Normal completion of the top-level program. Handled inline since every + // evaluation ends here. + if (ABSL_PREDICT_TRUE(pc_ == execution_path_.size() && call_stack_.empty())) { + return nullptr; + } + return ReturnFromSubexpression(); +} + +// Kept out of line so that `Next()` stays small enough to inline into the +// `Evaluate` loop. +ABSL_ATTRIBUTE_NOINLINE const ExpressionStep* +ExecutionFrame::ReturnFromSubexpression() { while (true) { const size_t end_pos = execution_path_.size(); diff --git a/eval/eval/evaluator_core.h b/eval/eval/evaluator_core.h index f25be8448..fab393b8e 100644 --- a/eval/eval/evaluator_core.h +++ b/eval/eval/evaluator_core.h @@ -495,6 +495,12 @@ class ExecutionFrame : public ExecutionFrameBase { size_t expected_stack_size; }; + // Called by `Next()` when `pc_` reaches the end of the current execution + // path. If a subexpression is being evaluated, returns to the caller (storing + // the result in the caller's comprehension slot) and returns the caller's + // next step. Returns nullptr once the top-level expression is complete. + const ExpressionStep* ReturnFromSubexpression(); + size_t pc_; // pc_ - Program Counter. Current position on execution path. ExecutionPathView execution_path_; EvaluatorStack* absl_nonnull const value_stack_;