Skip to content

Commit c677bfe

Browse files
l46kokcopybara-github
authored andcommitted
Move fast-path unary/binary apply methods into an internal interface
PiperOrigin-RevId: 892616861
1 parent 05cb0a1 commit c677bfe

File tree

11 files changed

+111
-37
lines changed

11 files changed

+111
-37
lines changed

common/src/main/java/dev/cel/common/internal/DefaultMessageFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public Optional<Message.Builder> newBuilder(String messageName) {
5252
DefaultInstanceMessageFactory.getInstance().getPrototype(descriptor.get());
5353

5454
if (message.isPresent()) {
55-
return message.map(Message::toBuilder);
55+
return message.map(Message::newBuilderForType);
5656
}
5757

5858
return Optional.of(DynamicMessage.newBuilder(descriptor.get()));

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,7 @@ java_library(
790790
name = "function_overload",
791791
srcs = [
792792
"CelFunctionOverload.java",
793+
"OptimizedFunctionOverload.java",
793794
],
794795
tags = [
795796
],
@@ -805,6 +806,7 @@ cel_android_library(
805806
name = "function_overload_android",
806807
srcs = [
807808
"CelFunctionOverload.java",
809+
"OptimizedFunctionOverload.java",
808810
],
809811
deps = [
810812
":evaluation_exception",
@@ -1306,6 +1308,7 @@ java_library(
13061308
tags = [
13071309
],
13081310
deps = [
1311+
":evaluation_exception",
13091312
":function_overload",
13101313
"//:auto_value",
13111314
"//common/annotations",
@@ -1320,6 +1323,7 @@ cel_android_library(
13201323
tags = [
13211324
],
13221325
deps = [
1326+
":evaluation_exception",
13231327
":function_overload_android",
13241328
"//:auto_value",
13251329
"//common/annotations",

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import com.google.auto.value.AutoOneOf;
1818
import com.google.auto.value.AutoValue;
1919
import com.google.common.base.Preconditions;
20-
import com.google.common.base.Splitter;
2120
import com.google.common.collect.ImmutableList;
2221
import com.google.common.primitives.UnsignedLong;
2322
import com.google.errorprone.annotations.Immutable;
@@ -184,9 +183,13 @@ public static CelAttribute create(String rootIdentifier) {
184183
*/
185184
public static CelAttribute fromQualifiedIdentifier(String qualifiedIdentifier) {
186185
ImmutableList.Builder<Qualifier> qualifiers = ImmutableList.builder();
187-
Splitter.on(".")
188-
.split(qualifiedIdentifier)
189-
.forEach((element) -> qualifiers.add(Qualifier.ofString(element)));
186+
int start = 0;
187+
int next;
188+
while ((next = qualifiedIdentifier.indexOf('.', start)) != -1) {
189+
qualifiers.add(Qualifier.ofString(qualifiedIdentifier.substring(start, next)));
190+
start = next + 1;
191+
}
192+
qualifiers.add(Qualifier.ofString(qualifiedIdentifier.substring(start)));
190193
return new AutoValue_CelAttribute(qualifiers.build());
191194
}
192195

@@ -206,7 +209,7 @@ public CelAttribute qualify(Qualifier qualifier) {
206209
return EMPTY;
207210
}
208211
return new AutoValue_CelAttribute(
209-
ImmutableList.<Qualifier>builder().addAll(qualifiers()).add(qualifier).build());
212+
ImmutableList.<Qualifier>builderWithExpectedSize(qualifiers().size() + 1).addAll(qualifiers()).add(qualifier).build());
210213
}
211214

212215
@Override

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import com.google.auto.value.AutoValue;
2020
import com.google.common.base.Preconditions;
21-
import com.google.common.base.Splitter;
2221
import com.google.common.collect.ImmutableList;
2322
import com.google.errorprone.annotations.Immutable;
2423

@@ -62,9 +61,13 @@ public static CelAttributePattern create(String rootIdentifier) {
6261
*/
6362
public static CelAttributePattern fromQualifiedIdentifier(String qualifiedIdentifier) {
6463
ImmutableList.Builder<CelAttribute.Qualifier> qualifiers = ImmutableList.builder();
65-
Splitter.on(".")
66-
.split(qualifiedIdentifier)
67-
.forEach((String element) -> qualifiers.add(CelAttribute.Qualifier.ofString(element)));
64+
int start = 0;
65+
int next;
66+
while ((next = qualifiedIdentifier.indexOf('.', start)) != -1) {
67+
qualifiers.add(CelAttribute.Qualifier.ofString(qualifiedIdentifier.substring(start, next)));
68+
start = next + 1;
69+
}
70+
qualifiers.add(CelAttribute.Qualifier.ofString(qualifiedIdentifier.substring(start)));
6871
return new AutoValue_CelAttributePattern(qualifiers.build());
6972
}
7073

@@ -74,7 +77,7 @@ public static CelAttributePattern fromQualifiedIdentifier(String qualifiedIdenti
7477
/** Create a new attribute pattern that specifies a subfield of this pattern. */
7578
public CelAttributePattern qualify(CelAttribute.Qualifier qualifier) {
7679
return new AutoValue_CelAttributePattern(
77-
ImmutableList.<CelAttribute.Qualifier>builder()
80+
ImmutableList.<CelAttribute.Qualifier>builderWithExpectedSize(qualifiers().size() + 1)
7881
.addAll(qualifiers())
7982
.add(qualifier)
8083
.build());

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@ public interface CelFunctionBinding {
5151
boolean isStrict();
5252

5353
/** Create a unary function binding from the {@code overloadId}, {@code arg}, and {@code impl}. */
54-
@SuppressWarnings("unchecked")
54+
@SuppressWarnings("unchecked") // Safe from CelFunctionOverload.canHandle check before invocation
5555
static <T> CelFunctionBinding from(
5656
String overloadId, Class<T> arg, CelFunctionOverload.Unary<T> impl) {
5757
return from(
5858
overloadId,
5959
ImmutableList.of(arg),
60-
new CelFunctionOverload() {
60+
new OptimizedFunctionOverload() {
6161
@Override
6262
public Object apply(Object[] args) throws CelEvaluationException {
6363
return impl.apply((T) args[0]);
@@ -74,13 +74,13 @@ public Object apply(Object arg1) throws CelEvaluationException {
7474
* Create a binary function binding from the {@code overloadId}, {@code arg1}, {@code arg2}, and
7575
* {@code impl}.
7676
*/
77-
@SuppressWarnings("unchecked")
77+
@SuppressWarnings("unchecked") // Safe from CelFunctionOverload.canHandle check before invocation
7878
static <T1, T2> CelFunctionBinding from(
7979
String overloadId, Class<T1> arg1, Class<T2> arg2, CelFunctionOverload.Binary<T1, T2> impl) {
8080
return from(
8181
overloadId,
8282
ImmutableList.of(arg1, arg2),
83-
new CelFunctionOverload() {
83+
new OptimizedFunctionOverload() {
8484
@Override
8585
public Object apply(Object[] args) throws CelEvaluationException {
8686
return impl.apply((T1) args[0], (T2) args[1]);

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,6 @@ public interface CelFunctionOverload {
2626
/** Evaluate a set of arguments throwing a {@code CelException} on error. */
2727
Object apply(Object[] args) throws CelEvaluationException;
2828

29-
/** Fast-path for unary function execution to avoid Object[] allocation. */
30-
default Object apply(Object arg) throws CelEvaluationException {
31-
return apply(new Object[] {arg});
32-
}
33-
34-
/** Fast-path for binary function execution to avoid Object[] allocation. */
35-
default Object apply(Object arg1, Object arg2) throws CelEvaluationException {
36-
return apply(new Object[] {arg1, arg2});
37-
}
3829

3930
/**
4031
* Helper interface for describing unary functions where the type-parameter is used to improve

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ public abstract class CelResolvedOverload {
5252
/** The function definition. */
5353
public abstract CelFunctionOverload getDefinition();
5454

55+
/** Fast-path execution optimizations safely hidden from the public API. */
56+
@Internal
57+
abstract OptimizedFunctionOverload getOptimizedDefinition();
58+
59+
public Object invoke(Object[] args) throws CelEvaluationException {
60+
return getDefinition().apply(args);
61+
}
62+
63+
public Object invoke(Object arg) throws CelEvaluationException {
64+
return getOptimizedDefinition().apply(arg);
65+
}
66+
67+
public Object invoke(Object arg1, Object arg2) throws CelEvaluationException {
68+
return getOptimizedDefinition().apply(arg1, arg2);
69+
}
70+
5571
/**
5672
* Creates a new resolved overload from the given overload id, parameter types, and definition.
5773
*/
@@ -71,8 +87,17 @@ public static CelResolvedOverload of(
7187
CelFunctionOverload definition,
7288
boolean isStrict,
7389
List<Class<?>> parameterTypes) {
90+
OptimizedFunctionOverload optimizedDef =
91+
(definition instanceof OptimizedFunctionOverload)
92+
? (OptimizedFunctionOverload) definition
93+
: new OptimizedFunctionOverload() {
94+
@Override
95+
public Object apply(Object[] args) throws CelEvaluationException {
96+
return definition.apply(args);
97+
}
98+
};
7499
return new AutoValue_CelResolvedOverload(
75-
overloadId, ImmutableList.copyOf(parameterTypes), isStrict, definition);
100+
overloadId, ImmutableList.copyOf(parameterTypes), isStrict, definition, optimizedDef);
76101
}
77102

78103
/**

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,36 +202,41 @@ public DefaultDispatcher build() {
202202
OverloadEntry overloadEntry = entry.getValue();
203203
CelFunctionOverload overloadImpl = overloadEntry.overload();
204204

205-
CelFunctionOverload guardedApply;
205+
OptimizedFunctionOverload guardedApply;
206206
if (overloadImpl instanceof DynamicDispatchOverload) {
207207
// Dynamic dispatcher already does its own internal canHandle checks
208-
guardedApply = overloadImpl;
208+
guardedApply = (DynamicDispatchOverload) overloadImpl;
209209
} else {
210210
boolean isStrict = overloadEntry.isStrict();
211211
ImmutableList<Class<?>> argTypes = overloadEntry.argTypes();
212212

213+
OptimizedFunctionOverload optImpl =
214+
(overloadImpl instanceof OptimizedFunctionOverload)
215+
? (OptimizedFunctionOverload) overloadImpl
216+
: overloadImpl::apply;
217+
213218
guardedApply =
214-
new CelFunctionOverload() {
219+
new OptimizedFunctionOverload() {
215220
@Override
216221
public Object apply(Object[] args) throws CelEvaluationException {
217222
if (CelFunctionOverload.canHandle(args, argTypes, isStrict)) {
218-
return overloadImpl.apply(args);
223+
return optImpl.apply(args);
219224
}
220225
throw new CelOverloadNotFoundException(overloadId);
221226
}
222227

223228
@Override
224229
public Object apply(Object arg) throws CelEvaluationException {
225230
if (CelFunctionOverload.canHandle(arg, argTypes, isStrict)) {
226-
return overloadImpl.apply(arg);
231+
return optImpl.apply(arg);
227232
}
228233
throw new CelOverloadNotFoundException(overloadId);
229234
}
230235

231236
@Override
232237
public Object apply(Object arg1, Object arg2) throws CelEvaluationException {
233238
if (CelFunctionOverload.canHandle(arg1, arg2, argTypes, isStrict)) {
234-
return overloadImpl.apply(arg1, arg2);
239+
return optImpl.apply(arg1, arg2);
235240
}
236241
throw new CelOverloadNotFoundException(overloadId);
237242
}

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ private DynamicDispatchBinding(
126126
}
127127

128128
@Immutable
129-
static final class DynamicDispatchOverload implements CelFunctionOverload {
129+
static final class DynamicDispatchOverload implements OptimizedFunctionOverload {
130130
private final String functionName;
131131
private final ImmutableSet<CelFunctionBinding> overloadBindings;
132132

@@ -149,7 +149,11 @@ public Object apply(Object[] args) throws CelEvaluationException {
149149
public Object apply(Object arg) throws CelEvaluationException {
150150
for (CelFunctionBinding overload : overloadBindings) {
151151
if (CelFunctionOverload.canHandle(arg, overload.getArgTypes(), overload.isStrict())) {
152-
return overload.getDefinition().apply(arg);
152+
CelFunctionOverload def = overload.getDefinition();
153+
if (def instanceof OptimizedFunctionOverload) {
154+
return ((OptimizedFunctionOverload) def).apply(arg);
155+
}
156+
return def.apply(new Object[] {arg});
153157
}
154158
}
155159
throw new CelOverloadNotFoundException(
@@ -164,7 +168,11 @@ public Object apply(Object arg1, Object arg2) throws CelEvaluationException {
164168
for (CelFunctionBinding overload : overloadBindings) {
165169
if (CelFunctionOverload.canHandle(
166170
arg1, arg2, overload.getArgTypes(), overload.isStrict())) {
167-
return overload.getDefinition().apply(arg1, arg2);
171+
CelFunctionOverload def = overload.getDefinition();
172+
if (def instanceof OptimizedFunctionOverload) {
173+
return ((OptimizedFunctionOverload) def).apply(arg1, arg2);
174+
}
175+
return def.apply(new Object[] {arg1, arg2});
168176
}
169177
}
170178
throw new CelOverloadNotFoundException(
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2024 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+
15+
package dev.cel.runtime;
16+
17+
import com.google.errorprone.annotations.Immutable;
18+
19+
/**
20+
* Internal interface to support fast-path Unary and Binary evaluations, avoiding Object[]
21+
* allocation.
22+
*/
23+
@Immutable
24+
interface OptimizedFunctionOverload extends CelFunctionOverload {
25+
26+
/** Fast-path for unary function execution to avoid Object[] allocation. */
27+
default Object apply(Object arg) throws CelEvaluationException {
28+
return apply(new Object[] {arg});
29+
}
30+
31+
/** Fast-path for binary function execution to avoid Object[] allocation. */
32+
default Object apply(Object arg1, Object arg2) throws CelEvaluationException {
33+
return apply(new Object[] {arg1, arg2});
34+
}
35+
}

0 commit comments

Comments
 (0)