diff --git a/eval/compiler/BUILD b/eval/compiler/BUILD index dbd8d9c8b..6916c96a5 100644 --- a/eval/compiler/BUILD +++ b/eval/compiler/BUILD @@ -360,7 +360,6 @@ cc_test( "//base:ast", "//common:expr", "//common:value", - "//eval/eval:const_value_step", "//eval/eval:create_list_step", "//eval/eval:create_map_step", "//eval/eval:evaluator_core", diff --git a/eval/compiler/constant_folding.cc b/eval/compiler/constant_folding.cc index 93cb35e65..071f16186 100644 --- a/eval/compiler/constant_folding.cc +++ b/eval/compiler/constant_folding.cc @@ -50,7 +50,6 @@ using ::cel::builtin::kOr; using ::cel::builtin::kTernary; using ::cel::runtime_internal::ConvertConstant; using ::google::api::expr::runtime::CreateConstValueDirectStep; -using ::google::api::expr::runtime::CreateConstValueStep; using ::google::api::expr::runtime::EvaluationListener; using ::google::api::expr::runtime::ExecutionFrame; using ::google::api::expr::runtime::ExecutionPath; @@ -243,8 +242,7 @@ absl::Status ConstantFoldingExtension::OnPostVisit(PlannerContext& context, // Otherwise make a stack machine plan. ExecutionPath new_plan; - new_plan.push_back(ExpressionStep::MakeGenericStep( - CreateConstValueStep(std::move(value)), node.id())); + new_plan.push_back(ExpressionStep::MakeConstant(value, node.id())); return context.ReplaceSubplan(node, std::move(new_plan)); } diff --git a/eval/compiler/constant_folding_test.cc b/eval/compiler/constant_folding_test.cc index 1528f5a5d..8c6fcf54c 100644 --- a/eval/compiler/constant_folding_test.cc +++ b/eval/compiler/constant_folding_test.cc @@ -29,7 +29,6 @@ #include "common/value.h" #include "eval/compiler/flat_expr_builder_extensions.h" #include "eval/compiler/resolver.h" -#include "eval/eval/const_value_step.h" #include "eval/eval/create_list_step.h" #include "eval/eval/create_map_step.h" #include "eval/eval/evaluator_core.h" @@ -58,7 +57,6 @@ using ::cel::runtime_internal::IssueCollector; using ::cel::runtime_internal::NewTestingRuntimeEnv; using ::cel::expr::ParsedExpr; using ::google::api::expr::parser::Parse; -using ::google::api::expr::runtime::CreateConstValueStep; using ::google::api::expr::runtime::CreateCreateListStep; using ::google::api::expr::runtime::CreateCreateStructStepForMap; using ::google::api::expr::runtime::ExecutionPath; @@ -116,25 +114,25 @@ TEST_F(UpdatedConstantFoldingTest, SkipsTernary) { program_builder.EnterSubexpression(&call); // condition program_builder.EnterSubexpression(&condition); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::BoolValue(true)), condition.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::BoolValue(true), condition.id())); program_builder.ExitSubexpression(&condition); // true program_builder.EnterSubexpression(&true_branch); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::BoolValue(true)), true_branch.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::BoolValue(true), true_branch.id())); program_builder.ExitSubexpression(&true_branch); // false program_builder.EnterSubexpression(&false_branch); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::BoolValue(true)), false_branch.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::BoolValue(true), false_branch.id())); program_builder.ExitSubexpression(&false_branch); // ternary. - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::NullValue()), call.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::NullValue(), call.id())); program_builder.ExitSubexpression(&call); std::shared_ptr arena; @@ -179,20 +177,20 @@ TEST_F(UpdatedConstantFoldingTest, SkipsOr) { // left program_builder.EnterSubexpression(&left_condition); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::BoolValue(false)), left_condition.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::BoolValue(false), left_condition.id())); program_builder.ExitSubexpression(&left_condition); // right program_builder.EnterSubexpression(&right_condition); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::BoolValue(true)), right_condition.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::BoolValue(true), right_condition.id())); program_builder.ExitSubexpression(&right_condition); // op // Just a placeholder. - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::NullValue()), call.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::NullValue(), call.id())); program_builder.ExitSubexpression(&call); std::shared_ptr arena; @@ -234,20 +232,20 @@ TEST_F(UpdatedConstantFoldingTest, SkipsAnd) { // left program_builder.EnterSubexpression(&left_condition); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::BoolValue(true)), left_condition.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::BoolValue(true), left_condition.id())); program_builder.ExitSubexpression(&left_condition); // right program_builder.EnterSubexpression(&right_condition); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::BoolValue(false)), right_condition.id())); + program_builder.AddStep(ExpressionStep::MakeConstant(cel::BoolValue(false), + right_condition.id())); program_builder.ExitSubexpression(&right_condition); // op // Just a placeholder. - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::NullValue()), call.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::NullValue(), call.id())); program_builder.ExitSubexpression(&call); std::shared_ptr arena; @@ -289,14 +287,14 @@ TEST_F(UpdatedConstantFoldingTest, CreatesList) { // elem one program_builder.EnterSubexpression(&elem_one); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::IntValue(1L)), elem_one.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::IntValue(1L), elem_one.id())); program_builder.ExitSubexpression(&elem_one); // elem two program_builder.EnterSubexpression(&elem_two); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::IntValue(2L)), elem_two.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::IntValue(2L), elem_two.id())); program_builder.ExitSubexpression(&elem_two); // createlist @@ -349,32 +347,32 @@ TEST_F(UpdatedConstantFoldingTest, CreatesLargeList) { // 0 ASSERT_TRUE(program_builder.EnterSubexpression(&elem0) != nullptr); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::IntValue(1L)), elem0.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::IntValue(1L), elem0.id())); program_builder.ExitSubexpression(&elem0); // 1 ASSERT_TRUE(program_builder.EnterSubexpression(&elem1)); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::IntValue(2L)), elem1.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::IntValue(2L), elem1.id())); program_builder.ExitSubexpression(&elem1); // 2 ASSERT_TRUE(program_builder.EnterSubexpression(&elem2) != nullptr); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::IntValue(3L)), elem2.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::IntValue(3L), elem2.id())); program_builder.ExitSubexpression(&elem2); // 3 ASSERT_TRUE(program_builder.EnterSubexpression(&elem3) != nullptr); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::IntValue(4L)), elem3.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::IntValue(4L), elem3.id())); program_builder.ExitSubexpression(&elem3); // 4 ASSERT_TRUE(program_builder.EnterSubexpression(&elem4) != nullptr); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::IntValue(5L)), elem4.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::IntValue(5L), elem4.id())); program_builder.ExitSubexpression(&elem4); // createlist @@ -428,14 +426,14 @@ TEST_F(UpdatedConstantFoldingTest, CreatesMap) { // key program_builder.EnterSubexpression(&key); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::IntValue(1L)), key.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::IntValue(1L), key.id())); program_builder.ExitSubexpression(&key); // value program_builder.EnterSubexpression(&value); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::IntValue(2L)), value.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::IntValue(2L), value.id())); program_builder.ExitSubexpression(&value); // create map @@ -484,14 +482,14 @@ TEST_F(UpdatedConstantFoldingTest, CreatesInvalidMap) { // key program_builder.EnterSubexpression(&key); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::DoubleValue(1.0)), key.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::DoubleValue(1.0), key.id())); program_builder.ExitSubexpression(&key); // value program_builder.EnterSubexpression(&value); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::IntValue(2L)), value.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::IntValue(2L), value.id())); program_builder.ExitSubexpression(&value); // create map @@ -539,20 +537,20 @@ TEST_F(UpdatedConstantFoldingTest, ErrorsOnUnexpectedOrder) { program_builder.EnterSubexpression(&call); // left program_builder.EnterSubexpression(&left_condition); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::BoolValue(true)), left_condition.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::BoolValue(true), left_condition.id())); program_builder.ExitSubexpression(&left_condition); // right program_builder.EnterSubexpression(&right_condition); - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::BoolValue(false)), right_condition.id())); + program_builder.AddStep(ExpressionStep::MakeConstant(cel::BoolValue(false), + right_condition.id())); program_builder.ExitSubexpression(&right_condition); // op // Just a placeholder. - program_builder.AddStep(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::NullValue()), call.id())); + program_builder.AddStep( + ExpressionStep::MakeConstant(cel::NullValue(), call.id())); program_builder.ExitSubexpression(&call); std::shared_ptr arena; diff --git a/eval/compiler/flat_expr_builder.cc b/eval/compiler/flat_expr_builder.cc index 677918c7c..7cb94fe45 100644 --- a/eval/compiler/flat_expr_builder.cc +++ b/eval/compiler/flat_expr_builder.cc @@ -730,8 +730,8 @@ class FlatExprVisitor : public cel::AstVisitor { return; } - AddStep(CreateConstValueStep(std::move(converted_value).value()), - expr.id()); + AddStep(ExpressionStep::MakeConstant(std::move(converted_value).value(), + expr.id())); } struct SlotLookupResult { diff --git a/eval/compiler/flat_expr_builder_extensions_test.cc b/eval/compiler/flat_expr_builder_extensions_test.cc index a1e8ecd4b..db13f6ec6 100644 --- a/eval/compiler/flat_expr_builder_extensions_test.cc +++ b/eval/compiler/flat_expr_builder_extensions_test.cc @@ -55,6 +55,17 @@ using ::testing::ElementsAre; using ::testing::IsEmpty; using ::testing::Optional; +class TestStepLogic : public ExpressionStepLogic { + public: + absl::Status Evaluate(ExecutionFrame* frame) const override { + return absl::OkStatus(); + } +}; + +std::unique_ptr MakeTestStepLogic() { + return std::make_unique(); +} + using Subexpression = ProgramBuilder::Subexpression; class PlannerContextTest : public testing::Test { @@ -94,9 +105,9 @@ struct SimpleTreeSteps { absl::StatusOr InitSimpleTree( const Expr& a, const Expr& b, const Expr& c, ProgramBuilder& program_builder) { - auto a_step = CreateConstValueStep(cel::NullValue()); - auto b_step = CreateConstValueStep(cel::NullValue()); - auto c_step = CreateConstValueStep(cel::NullValue()); + auto a_step = MakeTestStepLogic(); + auto b_step = MakeTestStepLogic(); + auto c_step = MakeTestStepLogic(); SimpleTreeSteps result{a_step.get(), b_step.get(), c_step.get()}; @@ -163,7 +174,7 @@ TEST_F(PlannerContextTest, ReplacePlan) { ExecutionPath new_a; - auto new_a_step = CreateConstValueStep(cel::NullValue()); + auto new_a_step = MakeTestStepLogic(); const ExpressionStepLogic* new_a_step_ptr = new_a_step.get(); new_a.push_back(ExpressionStep::MakeGenericStep(std::move(new_a_step), -1)); @@ -253,10 +264,10 @@ TEST_F(PlannerContextTest, ReplacePlanUpdatesSibling) { ExecutionPath new_b; - auto b1_step = CreateConstValueStep(cel::NullValue()); + auto b1_step = MakeTestStepLogic(); const ExpressionStepLogic* b1_step_ptr = b1_step.get(); new_b.push_back(ExpressionStep::MakeGenericStep(std::move(b1_step), -1)); - auto b2_step = CreateConstValueStep(cel::NullValue()); + auto b2_step = MakeTestStepLogic(); const ExpressionStepLogic* b2_step_ptr = b2_step.get(); new_b.push_back(ExpressionStep::MakeGenericStep(std::move(b2_step), -1)); @@ -302,7 +313,7 @@ TEST_F(PlannerContextTest, AddSubplanStep) { ASSERT_OK_AND_ASSIGN(auto plan_steps, InitSimpleTree(a, b, c, program_builder)); - auto b2_step = CreateConstValueStep(cel::NullValue()); + auto b2_step = MakeTestStepLogic(); const ExpressionStepLogic* b2_step_ptr = b2_step.get(); @@ -331,7 +342,7 @@ TEST_F(PlannerContextTest, AddSubplanStepFailsOnUnknownNode) { ASSERT_THAT(InitSimpleTree(a, b, c, program_builder).status(), IsOk()); - auto b2_step = CreateConstValueStep(cel::NullValue()); + auto b2_step = MakeTestStepLogic(); std::shared_ptr arena; PlannerContext context(env_, resolver_, options_, @@ -478,7 +489,7 @@ TEST_F(ProgramBuilderTest, ExtractWorks) { program_builder.EnterSubexpression(&b); program_builder.ExitSubexpression(&b); - auto a_step = CreateConstValueStep(cel::NullValue()); + auto a_step = MakeTestStepLogic(); program_builder.AddStep( ExpressionStep::MakeGenericStep(std::move(a_step), -1)); program_builder.EnterSubexpression(&c); diff --git a/eval/compiler/regex_precompilation_optimization.cc b/eval/compiler/regex_precompilation_optimization.cc index 46c8817af..fa0d289f2 100644 --- a/eval/compiler/regex_precompilation_optimization.cc +++ b/eval/compiler/regex_precompilation_optimization.cc @@ -194,12 +194,11 @@ class RegexPrecompilationOptimization : public ProgramOptimizer { } else { // otherwise stack-machine program. ExecutionPathView re_plan = context.GetSubplan(re_expr); - if (re_plan.size() == 1 && re_plan[0].IsGenericStep() && - re_plan[0].GetGenericStep()->GetNativeTypeId() == - NativeTypeId::For()) { - constant = - down_cast(re_plan[0].GetGenericStep()) - ->value(); + if (re_plan.size() == 1) { + cel::Value val; + if (GetIfConstant(re_plan[0], val)) { + constant = std::move(val); + } } } diff --git a/eval/eval/BUILD b/eval/eval/BUILD index 1b4de3631..de692b8bf 100644 --- a/eval/eval/BUILD +++ b/eval/eval/BUILD @@ -48,6 +48,7 @@ cc_library( "//base:data", "//common:native_type", "//common:value", + "//common:value_kind", "//runtime", "//runtime:activation_interface", "//runtime:runtime_options", @@ -182,7 +183,6 @@ cc_library( deps = [ ":compiler_constant_step", ":direct_expression_step", - ":evaluator_core", "//common:value", "@com_google_absl//absl/status:statusor", ], @@ -732,6 +732,7 @@ cc_test( "//runtime:standard_functions", "//runtime/internal:runtime_env_testing", "@com_google_absl//absl/status", + "@com_google_absl//absl/status:status_macros", "@com_google_absl//absl/status:status_matchers", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", @@ -1137,7 +1138,6 @@ cc_library( ":attribute_trail", ":direct_expression_step", ":evaluator_core", - ":expression_step_base", "//common:native_type", "//common:value", "@com_google_absl//absl/status", @@ -1148,7 +1148,9 @@ cc_test( name = "compiler_constant_step_test", srcs = ["compiler_constant_step_test.cc"], deps = [ + ":attribute_trail", ":compiler_constant_step", + ":direct_expression_step", ":evaluator_core", "//common:native_type", "//common:value", diff --git a/eval/eval/compiler_constant_step.cc b/eval/eval/compiler_constant_step.cc index 44a03cecd..c1b46b92e 100644 --- a/eval/eval/compiler_constant_step.cc +++ b/eval/eval/compiler_constant_step.cc @@ -28,10 +28,4 @@ absl::Status DirectCompilerConstantStep::Evaluate( return absl::OkStatus(); } -absl::Status CompilerConstantStep::Evaluate(ExecutionFrame* frame) const { - frame->value_stack().Push(value_); - - return absl::OkStatus(); -} - } // namespace google::api::expr::runtime diff --git a/eval/eval/compiler_constant_step.h b/eval/eval/compiler_constant_step.h index 967f6512f..6708e02de 100644 --- a/eval/eval/compiler_constant_step.h +++ b/eval/eval/compiler_constant_step.h @@ -22,8 +22,6 @@ #include "common/value.h" #include "eval/eval/attribute_trail.h" #include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" -#include "eval/eval/expression_step_base.h" namespace google::api::expr::runtime { @@ -49,27 +47,6 @@ class DirectCompilerConstantStep : public DirectExpressionStep { cel::Value value_; }; -// ExpressionStep implementation that simply pushes a constant value on the -// stack. -// -// Overrides NativeTypeId ()o allow the FlatExprBuilder and extensions to -// inspect the underlying value. -class CompilerConstantStep : public ExpressionStepBase { - public: - explicit CompilerConstantStep(cel::Value value) : value_(std::move(value)) {} - - absl::Status Evaluate(ExecutionFrame* frame) const override; - - cel::NativeTypeId GetNativeTypeId() const override { - return cel::NativeTypeId::For(); - } - - const cel::Value& value() const { return value_; } - - private: - cel::Value value_; -}; - } // namespace google::api::expr::runtime #endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_COMPILER_CONSTANT_STEP_H_ diff --git a/eval/eval/compiler_constant_step_test.cc b/eval/eval/compiler_constant_step_test.cc index 8fb226813..181728479 100644 --- a/eval/eval/compiler_constant_step_test.cc +++ b/eval/eval/compiler_constant_step_test.cc @@ -13,10 +13,10 @@ // limitations under the License. #include "eval/eval/compiler_constant_step.h" -#include - #include "common/native_type.h" #include "common/value.h" +#include "eval/eval/attribute_trail.h" +#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "internal/testing.h" #include "internal/testing_descriptor_pool.h" @@ -30,43 +30,41 @@ namespace google::api::expr::runtime { namespace { -class CompilerConstantStepTest : public testing::Test { +class DirectCompilerConstantStepTest : public testing::Test { public: - CompilerConstantStepTest() - : type_provider_(cel::internal::GetTestingDescriptorPool()), - state_(2, 0, type_provider_, cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_) {} + DirectCompilerConstantStepTest() + : type_provider_(cel::internal::GetTestingDescriptorPool()) {} protected: google::protobuf::Arena arena_; cel::runtime_internal::RuntimeTypeProvider type_provider_; - FlatExpressionEvaluatorState state_; cel::Activation empty_activation_; cel::RuntimeOptions options_; }; -TEST_F(CompilerConstantStepTest, Evaluate) { - ExecutionPath path; - path.push_back(ExpressionStep::MakeGenericStep( - std::make_unique(cel::IntValue(42)))); - - ExecutionFrame frame(path, empty_activation_, options_, state_); +TEST_F(DirectCompilerConstantStepTest, Evaluate) { + ExecutionFrameBase frame(empty_activation_, options_, type_provider_, + cel::internal::GetTestingDescriptorPool(), + cel::internal::GetTestingMessageFactory(), &arena_); + DirectCompilerConstantStep step(cel::IntValue(42), -1); + cel::Value result; + AttributeTrail attr; - ASSERT_OK_AND_ASSIGN(cel::Value result, frame.Evaluate()); + ASSERT_THAT(step.Evaluate(frame, result, attr), absl_testing::IsOk()); EXPECT_EQ(result.GetInt().NativeValue(), 42); } -TEST_F(CompilerConstantStepTest, TypeId) { - CompilerConstantStep step(cel::IntValue(42)); +TEST_F(DirectCompilerConstantStepTest, TypeId) { + DirectCompilerConstantStep step(cel::IntValue(42), -1); - ExpressionStepLogic& abstract_step = step; + const DirectExpressionStep& abstract_step = step; EXPECT_EQ(abstract_step.GetNativeTypeId(), - cel::NativeTypeId::For()); + cel::NativeTypeId::For()); } -TEST_F(CompilerConstantStepTest, Value) { - CompilerConstantStep step(cel::IntValue(42)); +TEST_F(DirectCompilerConstantStepTest, Value) { + DirectCompilerConstantStep step(cel::IntValue(42), -1); EXPECT_EQ(step.value().GetInt().NativeValue(), 42); } diff --git a/eval/eval/const_value_step.h b/eval/eval/const_value_step.h index 8a08b580a..55425ceab 100644 --- a/eval/eval/const_value_step.h +++ b/eval/eval/const_value_step.h @@ -9,7 +9,6 @@ #include "common/value.h" #include "eval/eval/compiler_constant_step.h" #include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" namespace google::api::expr::runtime { @@ -19,12 +18,6 @@ inline std::unique_ptr CreateConstValueDirectStep( return std::make_unique(std::move(value), id); } -// Factory method for Constant AST node expression step. -inline std::unique_ptr CreateConstValueStep( - cel::Value value) { - return std::make_unique(std::move(value)); -} - } // namespace google::api::expr::runtime #endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_CONST_VALUE_STEP_H_ diff --git a/eval/eval/create_list_step_test.cc b/eval/eval/create_list_step_test.cc index ebb1ecb41..2faf1f11e 100644 --- a/eval/eval/create_list_step_test.cc +++ b/eval/eval/create_list_step_test.cc @@ -80,8 +80,8 @@ absl::StatusOr RunExpression( for (auto value : values) { auto& expr0 = create_list.mutable_elements().emplace_back().mutable_expr(); expr0.mutable_const_expr().set_int64_value(value); - path.push_back(ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::interop_internal::CreateIntValue(value)))); + path.push_back(ExpressionStep::MakeConstant( + cel::interop_internal::CreateIntValue(value))); } CEL_ASSIGN_OR_RETURN(auto step, CreateCreateListStep(create_list)); diff --git a/eval/eval/evaluator_core.cc b/eval/eval/evaluator_core.cc index 0aa6000a4..7b3cceb3c 100644 --- a/eval/eval/evaluator_core.cc +++ b/eval/eval/evaluator_core.cc @@ -15,6 +15,9 @@ #include "eval/eval/evaluator_core.h" #include +#include +#include +#include #include #include "absl/base/nullability.h" @@ -25,6 +28,7 @@ #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "common/value.h" +#include "common/value_kind.h" #include "runtime/activation_interface.h" #include "google/protobuf/arena.h" #include "google/protobuf/descriptor.h" @@ -102,6 +106,41 @@ class EvaluationStatus final { } // namespace +void ExpressionStep::Evaluate(ExecutionFrame* context) const { + switch (header_.kind) { + case ExpressionStepKind::kGenericLogic: { + EvaluationStatus s(u_.logic->Evaluate(context)); + if (!s.ok()) { + context->Abort(std::move(s).Consume()); + } + break; + } + case ExpressionStepKind::kIntConstant: + context->value_stack().Push(cel::IntValue(u_.int_val)); + break; + case ExpressionStepKind::kBoolConstant: + context->value_stack().Push(cel::BoolValue(u_.bool_val)); + break; + case ExpressionStepKind::kDoubleConstant: + context->value_stack().Push(cel::DoubleValue(u_.double_val)); + break; + case ExpressionStepKind::kNullConstant: + context->value_stack().Push(cel::NullValue()); + break; + case ExpressionStepKind::kUintConstant: + context->value_stack().Push(cel::UintValue(u_.uint_val)); + break; + case ExpressionStepKind::kOtherConstant: + context->value_stack().Push(*u_.other_val); + break; + case ExpressionStepKind::kMovedFrom: + default: + context->Abort( + absl::InternalError("ExpressionStep::Evaluate called on moved-from " + "object")); + } +} + absl::StatusOr ExecutionFrame::Evaluate( EvaluationListener& listener) { const size_t initial_stack_size = value_stack().size(); @@ -109,18 +148,13 @@ absl::StatusOr ExecutionFrame::Evaluate( if (!listener) { for (const ExpressionStep* expr = Next(); ABSL_PREDICT_TRUE(expr != nullptr); expr = Next()) { - if (EvaluationStatus status(expr->Evaluate(this)); !status.ok()) { - return std::move(status).Consume(); - } + expr->Evaluate(this); } } else { for (const ExpressionStep* expr = Next(); ABSL_PREDICT_TRUE(expr != nullptr); expr = Next()) { - if (EvaluationStatus status(expr->Evaluate(this)); !status.ok()) { - return std::move(status).Consume(); - } - - if (pc_ == 0 || !expr->comes_from_ast()) { + expr->Evaluate(this); + if (pc_ == 0 || !expr->comes_from_ast() || !abort_status().ok()) { // Skip if we just started a Call or if the step doesn't map to an // AST id. continue; @@ -140,6 +174,10 @@ absl::StatusOr ExecutionFrame::Evaluate( } } + if (!abort_status().ok()) { + return std::move(abort_status()); + } + const size_t final_stack_size = value_stack().size(); if (ABSL_PREDICT_FALSE(final_stack_size != initial_stack_size + 1 || final_stack_size == 0)) { @@ -174,4 +212,80 @@ absl::StatusOr FlatExpression::EvaluateWithCallback( return frame.Evaluate(frame.callback()); } +ExpressionStep ExpressionStep::MakeConstant(const cel::Value& value, + int64_t id) { + if (id < 0 || id > std::numeric_limits::max()) { + id = -1; + } + int32_t id32 = static_cast(id); + switch (value.kind()) { + case cel::ValueKind::kBool: { + ExpressionStep step(ExpressionStepKind::kBoolConstant, id32); + step.u_.bool_val = value.GetBool().NativeValue(); + return step; + } + case cel::ValueKind::kInt: { + ExpressionStep step(ExpressionStepKind::kIntConstant, id32); + step.u_.int_val = value.GetInt().NativeValue(); + return step; + } + case cel::ValueKind::kUint: { + ExpressionStep step(ExpressionStepKind::kUintConstant, id32); + step.u_.uint_val = value.GetUint().NativeValue(); + return step; + } + case cel::ValueKind::kDouble: { + ExpressionStep step(ExpressionStepKind::kDoubleConstant, id32); + step.u_.double_val = value.GetDouble().NativeValue(); + return step; + } + case cel::ValueKind::kNull: + return ExpressionStep(ExpressionStepKind::kNullConstant, id32); + default: { + ExpressionStep step(ExpressionStepKind::kOtherConstant, id32); + step.u_.other_val = new cel::Value(value); + return step; + } + } +} + +bool GetIfConstant(const ExpressionStep& step, cel::Value& out) { + switch (step.header_.kind) { + case ExpressionStepKind::kIntConstant: + out = cel::IntValue(step.u_.int_val); + return true; + case ExpressionStepKind::kBoolConstant: + out = cel::BoolValue(step.u_.bool_val); + return true; + case ExpressionStepKind::kDoubleConstant: + out = cel::DoubleValue(step.u_.double_val); + return true; + case ExpressionStepKind::kNullConstant: + out = cel::NullValue(); + return true; + case ExpressionStepKind::kUintConstant: + out = cel::UintValue(step.u_.uint_val); + return true; + case ExpressionStepKind::kOtherConstant: + out = *step.u_.other_val; + return true; + default: + return false; + } +} + +bool IsConstant(const ExpressionStep& step) { + switch (step.header_.kind) { + case ExpressionStepKind::kIntConstant: + case ExpressionStepKind::kBoolConstant: + case ExpressionStepKind::kDoubleConstant: + case ExpressionStepKind::kNullConstant: + case ExpressionStepKind::kUintConstant: + case ExpressionStepKind::kOtherConstant: + return true; + default: + return false; + } +} + } // namespace google::api::expr::runtime diff --git a/eval/eval/evaluator_core.h b/eval/eval/evaluator_core.h index f25be8448..4b2fb4ad3 100644 --- a/eval/eval/evaluator_core.h +++ b/eval/eval/evaluator_core.h @@ -62,6 +62,13 @@ class ExpressionStepLogic; enum class ExpressionStepKind : uint16_t { kMovedFrom = 0, kGenericLogic = 1, + kIntConstant = 2, + kBoolConstant = 3, + kDoubleConstant = 4, + kNullConstant = 5, + kUintConstant = 6, + // Any constant that can't be inlined. + kOtherConstant = 7, }; class ExpressionStep { @@ -72,6 +79,8 @@ class ExpressionStep { ExpressionStep(ExpressionStep&&); ExpressionStep& operator=(ExpressionStep&&); + ~ExpressionStep(); + // Returns corresponding expression object ID. // Requires that the input expression has IDs assigned to sub-expressions, // e.g. via a checker. The default value 0 is returned if there is no @@ -85,12 +94,7 @@ class ExpressionStep { // Returns if the execution step comes from AST. bool comes_from_ast() const { return header_.id >= 0; } - absl::Status Evaluate(ExecutionFrame* context) const; - - template - T Get() const; - template - bool Is() const; + void Evaluate(ExecutionFrame* context) const; const ExpressionStepLogic* GetGenericStep() const; bool IsGenericStep() const; @@ -104,6 +108,8 @@ class ExpressionStep { std::move(logic)); } + static ExpressionStep MakeConstant(const cel::Value& value, int64_t id = -1); + private: struct Header { ExpressionStepKind kind; @@ -111,18 +117,51 @@ class ExpressionStep { int32_t id; }; - friend void swap(ExpressionStep& lhs, ExpressionStep& rhs); - - ExpressionStep() = default; - + ExpressionStep() : header_{ExpressionStepKind::kMovedFrom, 0, -1} {} + ExpressionStep(ExpressionStepKind kind, int32_t id) : header_{kind, 0, id} { + header_ = {kind, 0, id}; + } ExpressionStep(ExpressionStepKind kind, int32_t id, std::unique_ptr logic) - : header_{kind, 0, id}, logic_(std::move(logic)) {} + : ExpressionStep(kind, id) { + u_.logic = logic.release(); + } + + friend void swap(ExpressionStep& lhs, ExpressionStep& rhs) { + using std::swap; + swap(lhs.header_, rhs.header_); + swap(lhs.u_, rhs.u_); + } + + friend bool GetIfConstant(const ExpressionStep& step, cel::Value& out); + friend bool IsConstant(const ExpressionStep& step); Header header_; - std::unique_ptr logic_; + // Note: ptr members are 'owned' by the step. + // ~ExpressionStep() is responsible for freeing. + union Data { + std::nullptr_t empty; + ExpressionStepLogic* logic; + int64_t int_val; + uint64_t uint_val; + double double_val; + bool bool_val; + cel::Value* other_val; + + Data() : empty(nullptr) {} + ~Data() {} + } u_; }; +#ifndef _MSC_VER +// Keep the core instruction size small to get better memory locality for the +// main program. +// +// MSVC does not support some of the bit-field packing used here so it will be +// larger. +static_assert(sizeof(ExpressionStep) == 16); +#endif + // Class Expression represents single execution step. class ExpressionStepLogic { public: @@ -346,6 +385,8 @@ class ExecutionFrameBase { return absl::OkStatus(); } + absl::Status& abort_status() { return abort_status_; } + protected: const cel::ActivationInterface* absl_nonnull activation_; EvaluationListener callback_; @@ -359,6 +400,7 @@ class ExecutionFrameBase { ComprehensionSlots* absl_nonnull slots_; const int max_iterations_; int iterations_; + absl::Status abort_status_; const bool attribute_tracking_enabled_; const bool missing_attribute_errors_enabled_; const bool unknown_processing_enabled_; @@ -387,7 +429,7 @@ class ExecutionFrame : public ExecutionFrameBase { execution_path_(flat), value_stack_(&state.value_stack()), iterator_stack_(&state.iterator_stack()), - subexpressions_() {} + subexpressions_(&execution_path_, 1) {} ExecutionFrame( absl::Span subexpressions, @@ -487,6 +529,15 @@ class ExecutionFrame : public ExecutionFrameBase { return *activation_; } + void Abort(absl::Status status) { + ABSL_DCHECK(!subexpressions_.empty()); + ABSL_DCHECK(!status.ok()); + abort_status_.Update(std::move(status)); + call_stack_.clear(); + execution_path_ = subexpressions_[0]; + pc_ = execution_path_.size(); + } + private: struct SubFrame { size_t return_pc; @@ -580,36 +631,43 @@ class FlatExpression { absl_nullable std::shared_ptr arena_; }; -// Implementation details. +// Helper functions for checking ExpressionStep kinds. Used for program +// optimization. -inline absl::Status ExpressionStep::Evaluate(ExecutionFrame* context) const { - ABSL_DCHECK_EQ(header_.kind, ExpressionStepKind::kGenericLogic); - return logic_->Evaluate(context); -} +// Checks if the step is a constant and if so, writes the value into `out`. +// Returns true if the step is a constant, false otherwise. +bool GetIfConstant(const ExpressionStep& step, cel::Value& out); + +// Checks if the step is a constant. +bool IsConstant(const ExpressionStep& step); + +// Implementation details. -template -inline T ExpressionStep::Get() const { - if constexpr (std::is_same_v) { - return GetGenericStep(); - } else { - static_assert(sizeof(T) == 0, "unsupported type"); +inline ExpressionStep::~ExpressionStep() { + switch (header_.kind) { + case ExpressionStepKind::kGenericLogic: + delete u_.logic; + break; + case ExpressionStepKind::kOtherConstant: + delete u_.other_val; + break; + case ExpressionStepKind::kMovedFrom: + case ExpressionStepKind::kIntConstant: + case ExpressionStepKind::kBoolConstant: + case ExpressionStepKind::kDoubleConstant: + case ExpressionStepKind::kNullConstant: + case ExpressionStepKind::kUintConstant: + break; + default: + ABSL_UNREACHABLE(); } - ABSL_UNREACHABLE(); + header_.kind = ExpressionStepKind::kMovedFrom; + u_.empty = nullptr; } inline const ExpressionStepLogic* ExpressionStep::GetGenericStep() const { ABSL_DCHECK_EQ(header_.kind, ExpressionStepKind::kGenericLogic); - return logic_.get(); -} - -template -inline bool ExpressionStep::Is() const { - if constexpr (std::is_same_v) { - return header_.kind == ExpressionStepKind::kGenericLogic; - } else { - static_assert(sizeof(T) == 0, "unsupported type"); - } - ABSL_UNREACHABLE(); + return u_.logic; } inline bool ExpressionStep::IsGenericStep() const { @@ -619,22 +677,17 @@ inline bool ExpressionStep::IsGenericStep() const { inline ExpressionStep::ExpressionStep(ExpressionStep&& other) : ExpressionStep() { using std::swap; - swap(*this, other); + swap(other, *this); } inline ExpressionStep& ExpressionStep::operator=(ExpressionStep&& other) { using std::swap; - swap(*this, other); + ExpressionStep tmp; + swap(*this, tmp); + swap(other, *this); return *this; } -inline void swap(ExpressionStep& lhs, ExpressionStep& rhs) { - using std::swap; - - swap(lhs.header_, rhs.header_); - swap(lhs.logic_, rhs.logic_); -} - } // namespace google::api::expr::runtime #endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_EVALUATOR_CORE_H_ diff --git a/eval/eval/evaluator_core_test.cc b/eval/eval/evaluator_core_test.cc index 873bc7365..91d03b749 100644 --- a/eval/eval/evaluator_core_test.cc +++ b/eval/eval/evaluator_core_test.cc @@ -121,6 +121,54 @@ TEST(EvaluatorCoreTest, SimpleEvaluatorTest) { EXPECT_THAT(value.Int64OrDie(), Eq(2)); } +TEST(EvaluatorCoreTest, MakeConstant) { + cel::runtime_internal::RuntimeTypeProvider type_provider( + cel::internal::GetTestingDescriptorPool()); + google::protobuf::Arena arena; + cel::Activation activation; + cel::RuntimeOptions options; + + auto evaluate_constant = + [&](const cel::Value& value) -> absl::StatusOr { + ExecutionPath path; + path.push_back(ExpressionStep::MakeConstant(value)); + FlatExpression expr(std::move(path), 0, type_provider, options); + auto state = expr.MakeEvaluatorState( + cel::internal::GetTestingDescriptorPool(), + cel::internal::GetTestingMessageFactory(), &arena); + return expr.EvaluateWithCallback(activation, nullptr, nullptr, state); + }; + + ASSERT_OK_AND_ASSIGN(auto bool_val, evaluate_constant(cel::BoolValue(true))); + EXPECT_TRUE(bool_val.IsBool()); + EXPECT_TRUE(bool_val.GetBool().NativeValue()); + + ASSERT_OK_AND_ASSIGN(auto int_val, evaluate_constant(cel::IntValue(42))); + EXPECT_TRUE(int_val.IsInt()); + EXPECT_EQ(int_val.GetInt().NativeValue(), 42); + + ASSERT_OK_AND_ASSIGN(auto uint_val, evaluate_constant(cel::UintValue(100))); + EXPECT_TRUE(uint_val.IsUint()); + EXPECT_EQ(uint_val.GetUint().NativeValue(), 100); + + ASSERT_OK_AND_ASSIGN(auto double_val, + evaluate_constant(cel::DoubleValue(3.14))); + EXPECT_TRUE(double_val.IsDouble()); + EXPECT_DOUBLE_EQ(double_val.GetDouble().NativeValue(), 3.14); + + ASSERT_OK_AND_ASSIGN(auto null_val, evaluate_constant(cel::NullValue())); + EXPECT_TRUE(null_val.IsNull()); + + ASSERT_OK_AND_ASSIGN(auto str_val, + evaluate_constant(cel::StringValue::Literal("hello"))); + EXPECT_TRUE(str_val.IsString()); + EXPECT_EQ(str_val.GetString().ToString(), "hello"); + + auto step_with_id = ExpressionStep::MakeConstant(cel::IntValue(1), 123); + EXPECT_EQ(step_with_id.id(), 123); + EXPECT_TRUE(step_with_id.comes_from_ast()); +} + class MockTraceCallback { public: MOCK_METHOD(void, Call, diff --git a/eval/eval/function_step_test.cc b/eval/eval/function_step_test.cc index 8adbda76c..a436a3281 100644 --- a/eval/eval/function_step_test.cc +++ b/eval/eval/function_step_test.cc @@ -8,6 +8,7 @@ #include #include "absl/status/status.h" +#include "absl/status/status_macros.h" #include "absl/status/status_matchers.h" #include "absl/status/statusor.h" #include "absl/strings/string_view.h" @@ -233,13 +234,13 @@ absl::StatusOr MakeTestFunctionStep( call.function(), call.has_target(), argument_matcher); int id = GetExprId(); if (!lazy_overloads.empty()) { - CEL_ASSIGN_OR_RETURN(auto logic, - CreateFunctionStep(call, id, lazy_overloads)); + ABSL_ASSIGN_OR_RETURN(auto logic, + CreateFunctionStep(call, id, lazy_overloads)); return ExpressionStep::MakeGenericStep(std::move(logic), id); } auto overloads = registry.FindStaticOverloads( call.function(), call.has_target(), argument_matcher); - CEL_ASSIGN_OR_RETURN(auto logic, CreateFunctionStep(call, id, overloads)); + ABSL_ASSIGN_OR_RETURN(auto logic, CreateFunctionStep(call, id, overloads)); return ExpressionStep::MakeGenericStep(std::move(logic), id); } @@ -540,11 +541,11 @@ TEST_P(FunctionStepTest, LazyFunctionOverloadingTest) { lt_call.mutable_args().emplace_back(); lt_call.set_function("_<_"); - auto step0 = ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::interop_internal::CreateIntValue(20))); + auto step0 = + ExpressionStep::MakeConstant(cel::interop_internal::CreateIntValue(20)); ASSERT_OK_AND_ASSIGN(auto step1, MakeTestFunctionStep(call1, registry)); - auto step2 = ExpressionStep::MakeGenericStep( - CreateConstValueStep(cel::interop_internal::CreateDoubleValue(21.9))); + auto step2 = ExpressionStep::MakeConstant( + cel::interop_internal::CreateDoubleValue(21.9)); ASSERT_OK_AND_ASSIGN(auto step3, MakeTestFunctionStep(call2, registry)); ASSERT_OK_AND_ASSIGN(auto step4, MakeTestFunctionStep(lt_call, registry)); diff --git a/eval/eval/lazy_init_step_test.cc b/eval/eval/lazy_init_step_test.cc index 00490dbe1..20105dfa0 100644 --- a/eval/eval/lazy_init_step_test.cc +++ b/eval/eval/lazy_init_step_test.cc @@ -19,7 +19,6 @@ #include "base/type_provider.h" #include "common/value.h" -#include "eval/eval/const_value_step.h" #include "eval/eval/evaluator_core.h" #include "internal/testing.h" #include "internal/testing_descriptor_pool.h" @@ -65,8 +64,7 @@ TEST_F(LazyInitStepTest, CreateCheckInitStepDoesInit) { path.push_back(ExpressionStep::MakeGenericStep(CreateLazyInitStep( /*slot_index=*/0, /*subexpression_index=*/1))); - subpath.push_back( - ExpressionStep::MakeGenericStep(CreateConstValueStep(cel::IntValue(42)))); + subpath.push_back(ExpressionStep::MakeConstant(cel::IntValue(42))); std::vector expression_table{path, subpath}; @@ -87,8 +85,7 @@ TEST_F(LazyInitStepTest, CreateCheckInitStepSkipInit) { path.push_back(ExpressionStep::MakeGenericStep(CreateLazyInitStep( /*slot_index=*/0, /*subexpression_index=*/-1))); - subpath.push_back( - ExpressionStep::MakeGenericStep(CreateConstValueStep(cel::IntValue(42)))); + subpath.push_back(ExpressionStep::MakeConstant(cel::IntValue(42))); std::vector expression_table{path, subpath};