Skip to content

Commit bdebf27

Browse files
committed
Painless: Add a simple cache for whitelist methods and fields. (#28142)
With support for multiple contexts we are adding some caching to the whitelist to keep the memory footprint for definitions from exploding.
1 parent 8536f86 commit bdebf27

File tree

1 file changed

+49
-15
lines changed
  • modules/lang-painless/src/main/java/org/elasticsearch/painless

1 file changed

+49
-15
lines changed

modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
*/
4242
public final class Definition {
4343

44+
private static final Map<String, Method> methodCache = new HashMap<>();
45+
private static final Map<String, Field> fieldCache = new HashMap<>();
46+
4447
private static final Pattern TYPE_NAME_PATTERN = Pattern.compile("^[_a-zA-Z][._a-zA-Z0-9]*$");
4548

4649
public static final String[] DEFINITION_FILES = new String[] {
@@ -533,6 +536,22 @@ Collection<Type> allSimpleTypes() {
533536
return simpleTypesMap.values();
534537
}
535538

539+
private static String buildMethodCacheKey(String structName, String methodName, List<Type> arguments) {
540+
StringBuilder key = new StringBuilder();
541+
key.append(structName);
542+
key.append(methodName);
543+
544+
for (Type argument : arguments) {
545+
key.append(argument.name);
546+
}
547+
548+
return key.toString();
549+
}
550+
551+
private static String buildFieldCacheKey(String structName, String fieldName, String typeName) {
552+
return structName + fieldName + typeName;
553+
}
554+
536555
// INTERNAL IMPLEMENTATION:
537556

538557
private final Map<Class<?>, RuntimeClass> runtimeMap;
@@ -836,8 +855,10 @@ private void addConstructor(String ownerStructName, Whitelist.Constructor whitel
836855
" with constructor parameters " + whitelistConstructor.painlessParameterTypeNames);
837856
}
838857

839-
painlessConstructor = new Method("<init>", ownerStruct, null, getTypeInternal("void"), painlessParametersTypes,
840-
asmConstructor, javaConstructor.getModifiers(), javaHandle);
858+
painlessConstructor = methodCache.computeIfAbsent(buildMethodCacheKey(ownerStruct.name, "<init>", painlessParametersTypes),
859+
key -> new Method("<init>", ownerStruct, null, getTypeInternal("void"), painlessParametersTypes,
860+
asmConstructor, javaConstructor.getModifiers(), javaHandle));
861+
841862
ownerStruct.constructors.put(painlessMethodKey, painlessConstructor);
842863
} else if (painlessConstructor.arguments.equals(painlessParametersTypes) == false){
843864
throw new IllegalArgumentException(
@@ -859,7 +880,7 @@ private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName,
859880
" [" + whitelistMethod.javaMethodName + "] for owner struct [" + ownerStructName + "].");
860881
}
861882

862-
Class<?> javaAugmentedClass = null;
883+
Class<?> javaAugmentedClass;
863884

864885
if (whitelistMethod.javaAugmentedClassName != null) {
865886
try {
@@ -869,6 +890,8 @@ private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName,
869890
"not found for method with name [" + whitelistMethod.javaMethodName + "] " +
870891
"and parameters " + whitelistMethod.painlessParameterTypeNames, cnfe);
871892
}
893+
} else {
894+
javaAugmentedClass = null;
872895
}
873896

874897
int augmentedOffset = javaAugmentedClass == null ? 0 : 1;
@@ -939,8 +962,10 @@ private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName,
939962
"[" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames);
940963
}
941964

942-
painlessMethod = new Method(whitelistMethod.javaMethodName, ownerStruct, null, painlessReturnType,
943-
painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle);
965+
painlessMethod = methodCache.computeIfAbsent(
966+
buildMethodCacheKey(ownerStruct.name, whitelistMethod.javaMethodName, painlessParametersTypes),
967+
key -> new Method(whitelistMethod.javaMethodName, ownerStruct, null, painlessReturnType, painlessParametersTypes,
968+
asmMethod, javaMethod.getModifiers(), javaMethodHandle));
944969
ownerStruct.staticMethods.put(painlessMethodKey, painlessMethod);
945970
} else if ((painlessMethod.name.equals(whitelistMethod.javaMethodName) && painlessMethod.rtn.equals(painlessReturnType) &&
946971
painlessMethod.arguments.equals(painlessParametersTypes)) == false) {
@@ -963,8 +988,10 @@ private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName,
963988
"[" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames);
964989
}
965990

966-
painlessMethod = new Method(whitelistMethod.javaMethodName, ownerStruct, javaAugmentedClass, painlessReturnType,
967-
painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle);
991+
painlessMethod = methodCache.computeIfAbsent(
992+
buildMethodCacheKey(ownerStruct.name, whitelistMethod.javaMethodName, painlessParametersTypes),
993+
key -> new Method(whitelistMethod.javaMethodName, ownerStruct, javaAugmentedClass, painlessReturnType,
994+
painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle));
968995
ownerStruct.methods.put(painlessMethodKey, painlessMethod);
969996
} else if ((painlessMethod.name.equals(whitelistMethod.javaMethodName) && painlessMethod.rtn.equals(painlessReturnType) &&
970997
painlessMethod.arguments.equals(painlessParametersTypes)) == false) {
@@ -1016,33 +1043,40 @@ private void addField(String ownerStructName, Whitelist.Field whitelistField) {
10161043
Field painlessField = ownerStruct.staticMembers.get(whitelistField.javaFieldName);
10171044

10181045
if (painlessField == null) {
1019-
painlessField = new Field(whitelistField.javaFieldName, javaField.getName(),
1020-
ownerStruct, painlessFieldType, javaField.getModifiers(), null, null);
1046+
painlessField = fieldCache.computeIfAbsent(
1047+
buildFieldCacheKey(ownerStruct.name, whitelistField.javaFieldName, painlessFieldType.name),
1048+
key -> new Field(whitelistField.javaFieldName, javaField.getName(),
1049+
ownerStruct, painlessFieldType, javaField.getModifiers(), null, null));
10211050
ownerStruct.staticMembers.put(whitelistField.javaFieldName, painlessField);
10221051
} else if (painlessField.type.equals(painlessFieldType) == false) {
10231052
throw new IllegalArgumentException("illegal duplicate static fields [" + whitelistField.javaFieldName + "] " +
10241053
"found within the struct [" + ownerStruct.name + "] with type [" + whitelistField.painlessFieldTypeName + "]");
10251054
}
10261055
} else {
1027-
MethodHandle javaMethodHandleGetter = null;
1028-
MethodHandle javaMethodHandleSetter = null;
1056+
MethodHandle javaMethodHandleGetter;
1057+
MethodHandle javaMethodHandleSetter;
10291058

10301059
try {
10311060
if (Modifier.isStatic(javaField.getModifiers()) == false) {
10321061
javaMethodHandleGetter = MethodHandles.publicLookup().unreflectGetter(javaField);
10331062
javaMethodHandleSetter = MethodHandles.publicLookup().unreflectSetter(javaField);
1063+
} else {
1064+
javaMethodHandleGetter = null;
1065+
javaMethodHandleSetter = null;
10341066
}
10351067
} catch (IllegalAccessException exception) {
10361068
throw new IllegalArgumentException("getter/setter [" + whitelistField.javaFieldName + "]" +
10371069
" not found for class [" + ownerStruct.clazz.getName() + "].");
10381070
}
10391071

1040-
Field painlessField = ownerStruct.staticMembers.get(whitelistField.javaFieldName);
1072+
Field painlessField = ownerStruct.members.get(whitelistField.javaFieldName);
10411073

10421074
if (painlessField == null) {
1043-
painlessField = new Field(whitelistField.javaFieldName, javaField.getName(),
1044-
ownerStruct, painlessFieldType, javaField.getModifiers(), javaMethodHandleGetter, javaMethodHandleSetter);
1045-
ownerStruct.staticMembers.put(whitelistField.javaFieldName, painlessField);
1075+
painlessField = fieldCache.computeIfAbsent(
1076+
buildFieldCacheKey(ownerStruct.name, whitelistField.javaFieldName, painlessFieldType.name),
1077+
key -> new Field(whitelistField.javaFieldName, javaField.getName(),
1078+
ownerStruct, painlessFieldType, javaField.getModifiers(), javaMethodHandleGetter, javaMethodHandleSetter));
1079+
ownerStruct.members.put(whitelistField.javaFieldName, painlessField);
10461080
} else if (painlessField.type.equals(painlessFieldType) == false) {
10471081
throw new IllegalArgumentException("illegal duplicate member fields [" + whitelistField.javaFieldName + "] " +
10481082
"found within the struct [" + ownerStruct.name + "] with type [" + whitelistField.painlessFieldTypeName + "]");

0 commit comments

Comments
 (0)