From 5eab0ae02dd6309b9721b8bfccc7c4cba7b69019 Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Sun, 4 Oct 2026 06:19:18 -0700 Subject: [PATCH] Fix some stream performance issues in CEL runtime PiperOrigin-RevId: 993192558 --- .../cel/common/internal/AdaptingTypes.java | 7 ++++- .../main/java/dev/cel/runtime/Activation.java | 27 ++++++++++++++----- .../dev/cel/runtime/DefaultInterpreter.java | 6 +++-- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/dev/cel/common/internal/AdaptingTypes.java b/common/src/main/java/dev/cel/common/internal/AdaptingTypes.java index 48158bd91..4cfe1ff4a 100644 --- a/common/src/main/java/dev/cel/common/internal/AdaptingTypes.java +++ b/common/src/main/java/dev/cel/common/internal/AdaptingTypes.java @@ -118,7 +118,12 @@ public Iterator iterator() { @Override public Object[] toArray() { - return delegate.stream().map(baseEl -> converter().convert(baseEl)).toArray(); + Object[] result = new Object[size()]; + int i = 0; + for (A a : delegate) { + result[i++] = converter().convert(a); + } + return result; } @Override diff --git a/runtime/src/main/java/dev/cel/runtime/Activation.java b/runtime/src/main/java/dev/cel/runtime/Activation.java index 074a461a2..3f74bc139 100644 --- a/runtime/src/main/java/dev/cel/runtime/Activation.java +++ b/runtime/src/main/java/dev/cel/runtime/Activation.java @@ -14,8 +14,6 @@ package dev.cel.runtime; -import static com.google.common.collect.ImmutableMap.toImmutableMap; - import com.google.common.base.Supplier; import com.google.common.collect.ImmutableMap; import com.google.protobuf.ByteString; @@ -109,11 +107,9 @@ public static Activation copyOf(Map map) { final ImmutableMap copy = (map instanceof ImmutableMap) ? (ImmutableMap) map - : map.entrySet().stream() - // ImmutableMaps are null-hostile, but the Activation is not, so make sure that null - // values and entries are skipped. - .filter(entry -> entry.getKey() != null && entry.getValue() != null) - .collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)); + : // ImmutableMaps are null-hostile, but the Activation is not, so make sure that null + // values and entries are skipped. + toImmutableMapFilteringNulls(map); return new Activation() { @Override @@ -128,6 +124,23 @@ public String toString() { }; } + /** + * Creates an {@link ImmutableMap} from the given {@link Map} filtering out null keys and values. + * + *

Used instead of the one-liner for performance reasons. + */ + private static ImmutableMap toImmutableMapFilteringNulls(Map map) { + ImmutableMap.Builder builder = ImmutableMap.builderWithExpectedSize(map.size()); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (key != null && value != null) { + builder.put(key, value); + } + } + return builder.buildOrThrow(); + } + /** * Extends this binder by another binder. Names will be attempted to first resolve in the other * binder, then in this binder. diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index fa22b1d00..2cf766af2 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -48,7 +48,6 @@ import dev.cel.common.values.CelByteString; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -499,7 +498,10 @@ private IntermediateResult dispatchCall( return IntermediateResult.create(attr, unknowns.get()); } - Object[] argArray = Arrays.stream(argResults).map(IntermediateResult::value).toArray(); + Object[] argArray = new Object[argResults.length]; + for (int i = 0; i < argResults.length; i++) { + argArray[i] = argResults[i].value(); + } ImmutableList overloadIds = reference.overloadIds(); CelResolvedOverload overload = findOverloadOrThrow(frame, expr, callExpr.function(), overloadIds, argArray);