Skip to content

Commit a8cc1a6

Browse files
l46kokcopybara-github
authored andcommitted
Add async execution engine and AsyncDriver
PiperOrigin-RevId: 983346214
1 parent 13ad4ff commit a8cc1a6

18 files changed

Lines changed: 3303 additions & 158 deletions

common/src/main/java/dev/cel/common/CelOverloadDecl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
* <p>An overload is declared in either a global function `Ex: f(x, ...)` or a method call style
3737
* `Ex: x.f(...)`.
3838
*/
39+
// TODO: Port https://github.com/cel-expr/cel-go/pull/1483 to support first-class
40+
// properties on declarations and bindings for late-bound and asynchronous functions.
3941
@AutoValue
4042
@Immutable
4143
public abstract class CelOverloadDecl {

runtime/planner/BUILD.bazel

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,48 @@ java_library(
2222
exports = ["//runtime/src/main/java/dev/cel/runtime/planner:planned_program"],
2323
)
2424

25+
cel_android_library(
26+
name = "planned_program_android",
27+
visibility = ["//:internal"],
28+
exports = ["//runtime/src/main/java/dev/cel/runtime/planner:planned_program_android"],
29+
)
30+
2531
java_library(
2632
name = "async_gate",
2733
testonly = 1,
2834
visibility = ["//:internal"],
2935
exports = ["//runtime/src/main/java/dev/cel/runtime/planner:async_gate"],
3036
)
3137

38+
cel_android_library(
39+
name = "async_gate_android",
40+
testonly = 1,
41+
visibility = ["//:internal"],
42+
exports = ["//runtime/src/main/java/dev/cel/runtime/planner:async_gate_android"],
43+
)
44+
3245
java_library(
3346
name = "async_completion_coordinator",
3447
testonly = 1,
3548
visibility = ["//:internal"],
3649
exports = ["//runtime/src/main/java/dev/cel/runtime/planner:async_completion_coordinator"],
3750
)
3851

52+
cel_android_library(
53+
name = "async_completion_coordinator_android",
54+
testonly = 1,
55+
visibility = ["//:internal"],
56+
exports = ["//runtime/src/main/java/dev/cel/runtime/planner:async_completion_coordinator_android"],
57+
)
58+
3959
java_library(
4060
name = "async_call_state_tracker",
4161
visibility = ["//:internal"],
4262
exports = ["//runtime/src/main/java/dev/cel/runtime/planner:async_call_state_tracker"],
4363
)
64+
65+
cel_android_library(
66+
name = "async_call_state_tracker_android",
67+
visibility = ["//:internal"],
68+
exports = ["//runtime/src/main/java/dev/cel/runtime/planner:async_call_state_tracker_android"],
69+
)

runtime/src/main/java/dev/cel/runtime/BUILD.bazel

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,6 @@ java_library(
829829
":function_binding",
830830
":function_resolver",
831831
":partial_vars",
832-
":program",
833832
":proto_message_runtime_equality",
834833
":runtime",
835834
":runtime_equality",
@@ -855,7 +854,6 @@ java_library(
855854
"//runtime:activation",
856855
"//runtime:interpretable",
857856
"//runtime:proto_message_activation_factory",
858-
"//runtime:resolved_overload",
859857
"//runtime/planner:planned_program",
860858
"//runtime/planner:program_planner",
861859
"//runtime/standard:type",
@@ -997,6 +995,7 @@ java_library(
997995
"//common/types:type_providers",
998996
"//common/values",
999997
"//common/values:cel_value_provider",
998+
"//runtime:async_options",
1000999
"//runtime:evaluation_exception",
10011000
"//runtime/planner:program_planner",
10021001
"//runtime/standard:standard_function",
@@ -1025,6 +1024,7 @@ cel_android_library(
10251024
"//common/types:type_providers_android",
10261025
"//common/values:cel_value_provider_android",
10271026
"//common/values:values_android",
1027+
"//runtime:async_options_android",
10281028
"//runtime:evaluation_exception",
10291029
"//runtime/planner:program_planner_android",
10301030
"//runtime/standard:standard_function_android",

runtime/src/main/java/dev/cel/runtime/CelFunctionBinding.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,7 @@ static ImmutableSet<CelFunctionBinding> fromOverloads(
188188
String functionName, Collection<CelFunctionBinding> overloadBindings) {
189189
checkArgument(!Strings.isNullOrEmpty(functionName), "Function name cannot be null or empty");
190190
checkArgument(!overloadBindings.isEmpty(), "You must provide at least one binding.");
191-
// TODO: Dynamic dispatch grouping does not currently support asynchronous
192-
// function overloads. In parsed-only mode, overloaded async functions must be resolved
193-
// at runtime via CelFunctionResolver.
191+
// TODO: Support dynamic overload resolution for asynchronous function overloads.
194192
for (CelFunctionBinding binding : overloadBindings) {
195193
checkArgument(
196194
!(binding.getDefinition() instanceof CelAsyncFunctionOverload),

runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java

Lines changed: 39 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -112,22 +112,7 @@ public Program createProgram(CelAbstractSyntaxTree ast) throws CelEvaluationExce
112112
return toRuntimeProgram(planner().plan(ast));
113113
}
114114

115-
private static final CelFunctionResolver EMPTY_FUNCTION_RESOLVER =
116-
new CelFunctionResolver() {
117-
@Override
118-
public Optional<CelResolvedOverload> findOverloadMatchingArgs(
119-
String functionName, Collection<String> overloadIds, Object[] args) {
120-
return Optional.empty();
121-
}
122-
123-
@Override
124-
public Optional<CelResolvedOverload> findOverloadMatchingArgs(
125-
String functionName, Object[] args) {
126-
return Optional.empty();
127-
}
128-
};
129-
130-
public Program toRuntimeProgram(dev.cel.runtime.Program program) {
115+
private Program toRuntimeProgram(PlannedProgram program) {
131116
return new Program() {
132117

133118
@Override
@@ -148,11 +133,9 @@ public Object eval(Map<String, ?> mapValue, CelFunctionResolver lateBoundFunctio
148133

149134
@Override
150135
public Object eval(Message message) throws CelEvaluationException {
151-
PlannedProgram plannedProgram = (PlannedProgram) program;
152-
return plannedProgram.evalOrThrow(
153-
plannedProgram.interpretable(),
154-
ProtoMessageActivationFactory.fromProto(message, plannedProgram.options()),
155-
EMPTY_FUNCTION_RESOLVER,
136+
return program.evalOrThrow(
137+
ProtoMessageActivationFactory.fromProto(message, program.options()),
138+
CelFunctionResolver.EMPTY,
156139
/* partialVars= */ null,
157140
/* listener= */ null);
158141
}
@@ -190,12 +173,6 @@ public ListenableFuture<Object> evalAsync(
190173
return program.evalAsync(mapValue, lateBoundFunctionResolver);
191174
}
192175

193-
@Override
194-
public ListenableFuture<Object> evalAsync(Message message) {
195-
throw new UnsupportedOperationException(
196-
"evalAsync is not supported by this Program implementation.");
197-
}
198-
199176
@Override
200177
public ListenableFuture<Object> evalAsync(CelVariableResolver resolver) {
201178
return program.evalAsync(resolver);
@@ -212,40 +189,42 @@ public ListenableFuture<Object> evalAsync(PartialVars partialVars) {
212189
return program.evalAsync(partialVars);
213190
}
214191

192+
@Override
193+
public ListenableFuture<Object> evalAsync(Message message) {
194+
checkNotNull(message, "message");
195+
return program.evalAsync(
196+
ProtoMessageActivationFactory.fromProto(message, program.options()),
197+
CelFunctionResolver.EMPTY,
198+
/* partialVars= */ null);
199+
}
200+
215201
@Override
216202
public Object trace(CelEvaluationListener listener) throws CelEvaluationException {
217-
return ((PlannedProgram) program)
218-
.trace(GlobalResolver.EMPTY, EMPTY_FUNCTION_RESOLVER, null, listener);
203+
return program.trace(GlobalResolver.EMPTY, CelFunctionResolver.EMPTY, null, listener);
219204
}
220205

221206
@Override
222207
public Object trace(Map<String, ?> mapValue, CelEvaluationListener listener)
223208
throws CelEvaluationException {
224-
return ((PlannedProgram) program)
225-
.trace(Activation.copyOf(mapValue), EMPTY_FUNCTION_RESOLVER, null, listener);
209+
return program.trace(
210+
Activation.copyOf(mapValue), CelFunctionResolver.EMPTY, null, listener);
226211
}
227212

228213
@Override
229214
public Object trace(Message message, CelEvaluationListener listener)
230215
throws CelEvaluationException {
231-
PlannedProgram plannedProgram = (PlannedProgram) program;
232-
return plannedProgram.evalOrThrow(
233-
plannedProgram.interpretable(),
234-
ProtoMessageActivationFactory.fromProto(message, plannedProgram.options()),
235-
EMPTY_FUNCTION_RESOLVER,
216+
return program.evalOrThrow(
217+
ProtoMessageActivationFactory.fromProto(message, program.options()),
218+
CelFunctionResolver.EMPTY,
236219
/* partialVars= */ null,
237220
listener);
238221
}
239222

240223
@Override
241224
public Object trace(CelVariableResolver resolver, CelEvaluationListener listener)
242225
throws CelEvaluationException {
243-
return ((PlannedProgram) program)
244-
.trace(
245-
(name) -> resolver.find(name).orElse(null),
246-
EMPTY_FUNCTION_RESOLVER,
247-
null,
248-
listener);
226+
return program.trace(
227+
(name) -> resolver.find(name).orElse(null), CelFunctionResolver.EMPTY, null, listener);
249228
}
250229

251230
@Override
@@ -254,12 +233,8 @@ public Object trace(
254233
CelFunctionResolver lateBoundFunctionResolver,
255234
CelEvaluationListener listener)
256235
throws CelEvaluationException {
257-
return ((PlannedProgram) program)
258-
.trace(
259-
(name) -> resolver.find(name).orElse(null),
260-
lateBoundFunctionResolver,
261-
null,
262-
listener);
236+
return program.trace(
237+
(name) -> resolver.find(name).orElse(null), lateBoundFunctionResolver, null, listener);
263238
}
264239

265240
@Override
@@ -268,23 +243,22 @@ public Object trace(
268243
CelFunctionResolver lateBoundFunctionResolver,
269244
CelEvaluationListener listener)
270245
throws CelEvaluationException {
271-
return ((PlannedProgram) program)
272-
.trace(Activation.copyOf(mapValue), lateBoundFunctionResolver, null, listener);
246+
return program.trace(
247+
Activation.copyOf(mapValue), lateBoundFunctionResolver, null, listener);
273248
}
274249

275250
@Override
276251
public Object trace(PartialVars partialVars, CelEvaluationListener listener)
277252
throws CelEvaluationException {
278-
return ((PlannedProgram) program)
279-
.trace(
280-
(name) -> partialVars.resolver().find(name).orElse(null),
281-
EMPTY_FUNCTION_RESOLVER,
282-
partialVars,
283-
listener);
253+
return program.trace(
254+
(name) -> partialVars.resolver().find(name).orElse(null),
255+
CelFunctionResolver.EMPTY,
256+
partialVars,
257+
listener);
284258
}
285259

286260
@Override
287-
public Object advanceEvaluation(UnknownContext context) throws CelEvaluationException {
261+
public Object advanceEvaluation(UnknownContext context) {
288262
throw new UnsupportedOperationException("Unsupported operation.");
289263
}
290264
};
@@ -347,6 +321,10 @@ public abstract Builder setAsyncEvaluationOptions(
347321
@Override
348322
public abstract CelValueProvider valueProvider();
349323

324+
abstract CelAsyncEvaluationOptions asyncEvaluationOptions();
325+
326+
abstract Optional<ListeningExecutorService> asyncExecutor();
327+
350328
abstract CelStandardFunctions standardFunctions();
351329

352330
abstract ExtensionRegistry extensionRegistry();
@@ -604,7 +582,10 @@ public CelRuntime build() {
604582
celValueConverter,
605583
container(),
606584
options(),
607-
lateBoundFunctionNamesBuilder().build());
585+
lateBoundFunctionNamesBuilder().build(),
586+
runtimeEquality,
587+
asyncEvaluationOptions(),
588+
asyncExecutor().orElse(null));
608589
setPlanner(planner);
609590

610591
setFunctionBindings(ImmutableMap.copyOf(mutableFunctionBindings));

runtime/src/main/java/dev/cel/runtime/LiteRuntimeImpl.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,10 @@ public CelLiteRuntime build() {
229229
celValueProvider.celValueConverter(),
230230
container,
231231
celOptions,
232-
lateBoundFunctionNamesBuilder.build());
232+
lateBoundFunctionNamesBuilder.build(),
233+
// TODO: Support async eval in lite runtime.
234+
CelAsyncEvaluationOptions.defaultOptions(),
235+
/* asyncExecutor= */ null);
233236

234237
return new LiteRuntimeImpl(
235238
planner,

runtime/src/main/java/dev/cel/runtime/RuntimeEquality.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,12 @@ public Optional<Object> findInMap(Map<?, ?> map, Object index) {
135135
* comparable even if they are not of the same type, where type differences are usually trivially
136136
* false.
137137
*/
138-
@SuppressWarnings({"rawtypes", "unchecked"})
138+
@SuppressWarnings({"rawtypes", "unchecked", "ReferenceEquality"})
139139
public boolean objectEquals(Object x, Object y) {
140140
if (celOptions.disableCelStandardEquality()) {
141141
return Objects.equals(x, y);
142142
}
143-
if (x == y) {
143+
if (x == y && !isNan(x)) {
144144
return true;
145145
}
146146
x = runtimeHelpers.adaptValue(x);
@@ -278,6 +278,10 @@ private static Optional<Long> unsignedToLongLossless(UnsignedLong v) {
278278
return Optional.empty();
279279
}
280280

281+
private static boolean isNan(Object value) {
282+
return value instanceof Number && Double.isNaN(((Number) value).doubleValue());
283+
}
284+
281285
RuntimeEquality(RuntimeHelpers runtimeHelpers, CelOptions celOptions) {
282286
this.runtimeHelpers = runtimeHelpers;
283287
this.celOptions = celOptions;

0 commit comments

Comments
 (0)