/proc/self/cwd/runtime/internal/runtime_impl.cc
Line | Count | Source |
1 | | // Copyright 2023 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | #include "runtime/internal/runtime_impl.h" |
15 | | |
16 | | #include <memory> |
17 | | #include <utility> |
18 | | |
19 | | #include "absl/base/nullability.h" |
20 | | #include "absl/log/absl_check.h" |
21 | | #include "absl/status/statusor.h" |
22 | | #include "base/ast.h" |
23 | | #include "base/type_provider.h" |
24 | | #include "common/native_type.h" |
25 | | #include "common/value.h" |
26 | | #include "eval/eval/attribute_trail.h" |
27 | | #include "eval/eval/comprehension_slots.h" |
28 | | #include "eval/eval/direct_expression_step.h" |
29 | | #include "eval/eval/evaluator_core.h" |
30 | | #include "internal/casts.h" |
31 | | #include "internal/status_macros.h" |
32 | | #include "runtime/activation_interface.h" |
33 | | #include "runtime/runtime.h" |
34 | | #include "google/protobuf/arena.h" |
35 | | |
36 | | namespace cel::runtime_internal { |
37 | | namespace { |
38 | | |
39 | | using ::google::api::expr::runtime::AttributeTrail; |
40 | | using ::google::api::expr::runtime::ComprehensionSlots; |
41 | | using ::google::api::expr::runtime::DirectExpressionStep; |
42 | | using ::google::api::expr::runtime::ExecutionFrameBase; |
43 | | using ::google::api::expr::runtime::FlatExpression; |
44 | | using ::google::api::expr::runtime::WrappedDirectStep; |
45 | | |
46 | | class ProgramImpl final : public TraceableProgram { |
47 | | public: |
48 | | using EvaluationListener = TraceableProgram::EvaluationListener; |
49 | | ProgramImpl( |
50 | | const std::shared_ptr<const RuntimeImpl::Environment>& environment, |
51 | | FlatExpression impl) |
52 | 0 | : environment_(environment), impl_(std::move(impl)) {} |
53 | | |
54 | | absl::StatusOr<Value> TraceImpl( |
55 | | const ActivationInterface& activation, |
56 | | EvaluationListener evaluation_listener, google::protobuf::Arena* absl_nonnull arena, |
57 | 0 | const EvaluateOptions& options) const override { |
58 | 0 | ABSL_DCHECK(arena != nullptr); |
59 | 0 | auto state = |
60 | 0 | impl_.MakeEvaluatorState(environment_->descriptor_pool.get(), |
61 | 0 | options.message_factory != nullptr |
62 | 0 | ? options.message_factory |
63 | 0 | : environment_->MutableMessageFactory(), |
64 | 0 | arena); |
65 | 0 | return impl_.EvaluateWithCallback(activation, options.embedder_context, |
66 | 0 | std::move(evaluation_listener), state); |
67 | 0 | } |
68 | | |
69 | 0 | const TypeProvider& GetTypeProvider() const override { |
70 | 0 | return environment_->type_registry.GetComposedTypeProvider(); |
71 | 0 | } |
72 | | |
73 | | private: |
74 | | // Keep the Runtime environment alive while programs reference it. |
75 | | std::shared_ptr<const RuntimeImpl::Environment> environment_; |
76 | | FlatExpression impl_; |
77 | | }; |
78 | | |
79 | | class RecursiveProgramImpl final : public TraceableProgram { |
80 | | public: |
81 | | using EvaluationListener = TraceableProgram::EvaluationListener; |
82 | | RecursiveProgramImpl( |
83 | | const std::shared_ptr<const RuntimeImpl::Environment>& environment, |
84 | | FlatExpression impl, const DirectExpressionStep* absl_nonnull root) |
85 | 0 | : environment_(environment), impl_(std::move(impl)), root_(root) {} |
86 | | |
87 | | absl::StatusOr<Value> TraceImpl( |
88 | | const ActivationInterface& activation, |
89 | | EvaluationListener evaluation_listener, google::protobuf::Arena* absl_nonnull arena, |
90 | 0 | const EvaluateOptions& options) const override { |
91 | 0 | ABSL_DCHECK(arena != nullptr); |
92 | 0 | ComprehensionSlots slots(impl_.comprehension_slots_size()); |
93 | 0 | ExecutionFrameBase frame(activation, std::move(evaluation_listener), |
94 | 0 | impl_.options(), GetTypeProvider(), |
95 | 0 | environment_->descriptor_pool.get(), |
96 | 0 | options.message_factory != nullptr |
97 | 0 | ? options.message_factory |
98 | 0 | : environment_->MutableMessageFactory(), |
99 | 0 | arena, options.embedder_context, slots); |
100 | |
|
101 | 0 | Value result; |
102 | 0 | AttributeTrail attribute; |
103 | 0 | CEL_RETURN_IF_ERROR(root_->Evaluate(frame, result, attribute)); |
104 | | |
105 | 0 | return result; |
106 | 0 | } |
107 | | |
108 | 0 | const TypeProvider& GetTypeProvider() const override { |
109 | 0 | return environment_->type_registry.GetComposedTypeProvider(); |
110 | 0 | } |
111 | | |
112 | | private: |
113 | | // Keep the Runtime environment alive while programs reference it. |
114 | | std::shared_ptr<const RuntimeImpl::Environment> environment_; |
115 | | FlatExpression impl_; |
116 | | const DirectExpressionStep* absl_nonnull root_; |
117 | | }; |
118 | | |
119 | | } // namespace |
120 | | |
121 | | absl::StatusOr<std::unique_ptr<Program>> RuntimeImpl::CreateProgram( |
122 | | std::unique_ptr<Ast> ast, |
123 | 0 | const Runtime::CreateProgramOptions& options) const { |
124 | 0 | return CreateTraceableProgram(std::move(ast), options); |
125 | 0 | } |
126 | | |
127 | | absl::StatusOr<std::unique_ptr<TraceableProgram>> |
128 | | RuntimeImpl::CreateTraceableProgram( |
129 | | std::unique_ptr<Ast> ast, |
130 | 0 | const Runtime::CreateProgramOptions& options) const { |
131 | 0 | CEL_ASSIGN_OR_RETURN(auto flat_expr, expr_builder_.CreateExpressionImpl( |
132 | 0 | std::move(ast), options.issues)); |
133 | | |
134 | | // Special case if the program is fully recursive. |
135 | | // |
136 | | // This implementation avoids unnecessary allocs at evaluation time which |
137 | | // improves performance notably for small expressions. |
138 | 0 | if (expr_builder_.options().max_recursion_depth != 0 && |
139 | 0 | !flat_expr.subexpressions().empty() && |
140 | | // mainline expression is exactly one recursive step. |
141 | 0 | flat_expr.subexpressions().front().size() == 1 && |
142 | 0 | flat_expr.subexpressions().front().front()->GetNativeTypeId() == |
143 | 0 | NativeTypeId::For<WrappedDirectStep>()) { |
144 | 0 | const DirectExpressionStep* root = |
145 | 0 | internal::down_cast<const WrappedDirectStep*>( |
146 | 0 | flat_expr.subexpressions().front().front().get()) |
147 | 0 | ->wrapped(); |
148 | 0 | return std::make_unique<RecursiveProgramImpl>(environment_, |
149 | 0 | std::move(flat_expr), root); |
150 | 0 | } |
151 | | |
152 | 0 | return std::make_unique<ProgramImpl>(environment_, std::move(flat_expr)); |
153 | 0 | } |
154 | | |
155 | 0 | bool TestOnly_IsRecursiveImpl(const Program* program) { |
156 | 0 | return dynamic_cast<const RecursiveProgramImpl*>(program) != nullptr; |
157 | 0 | } |
158 | | |
159 | | } // namespace cel::runtime_internal |