Skip to content

Commit 502eb35

Browse files
committed
Painless: Modify Loader to Load Classes Directly from Definition (#28088)
1 parent 3db1a3d commit 502eb35

File tree

12 files changed

+149
-94
lines changed

12 files changed

+149
-94
lines changed

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,28 @@ final class Compiler {
6969
*/
7070
static final class Loader extends SecureClassLoader {
7171
private final AtomicInteger lambdaCounter = new AtomicInteger(0);
72+
private final Definition definition;
7273

7374
/**
7475
* @param parent The parent ClassLoader.
7576
*/
76-
Loader(ClassLoader parent) {
77+
Loader(ClassLoader parent, Definition definition) {
7778
super(parent);
79+
80+
this.definition = definition;
81+
}
82+
83+
/**
84+
* Will check to see if the {@link Class} has already been loaded when
85+
* the {@link Definition} was initially created. Allows for {@link Whitelist}ed
86+
* classes to be loaded from other modules/plugins without a direct relationship
87+
* to the module's/plugin's {@link ClassLoader}.
88+
*/
89+
@Override
90+
public Class<?> findClass(String name) throws ClassNotFoundException {
91+
Class<?> found = definition.getClassFromBinaryName(name);
92+
93+
return found != null ? found : super.findClass(name);
7894
}
7995

8096
/**
@@ -116,6 +132,14 @@ int newLambdaIdentifier() {
116132
}
117133
}
118134

135+
/**
136+
* Return a new {@link Loader} for a script using the
137+
* {@link Compiler}'s specified {@link Definition}.
138+
*/
139+
public Loader createLoader(ClassLoader parent) {
140+
return new Loader(parent, definition);
141+
}
142+
119143
/**
120144
* The class/interface the script is guaranteed to derive/implement.
121145
*/

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public final class Definition {
4343

4444
private static final Pattern TYPE_NAME_PATTERN = Pattern.compile("^[_a-zA-Z][._a-zA-Z0-9]*$");
4545

46-
private static final String[] DEFINITION_FILES = new String[] {
46+
public static final String[] DEFINITION_FILES = new String[] {
4747
"org.elasticsearch.txt",
4848
"java.lang.txt",
4949
"java.math.txt",
@@ -522,6 +522,12 @@ public RuntimeClass getRuntimeClass(Class<?> clazz) {
522522
return runtimeMap.get(clazz);
523523
}
524524

525+
public Class<?> getClassFromBinaryName(String name) {
526+
Struct struct = structsMap.get(name.replace('$', '.'));
527+
528+
return struct == null ? null : struct.clazz;
529+
}
530+
525531
/** Collection of all simple types. Used by {@code PainlessDocGenerator} to generate an API reference. */
526532
Collection<Type> allSimpleTypes() {
527533
return simpleTypesMap.values();
@@ -535,7 +541,7 @@ Collection<Type> allSimpleTypes() {
535541

536542
public AnalyzerCaster caster;
537543

538-
private Definition(List<Whitelist> whitelists) {
544+
public Definition(List<Whitelist> whitelists) {
539545
structsMap = new HashMap<>();
540546
simpleTypesMap = new HashMap<>();
541547
runtimeMap = new HashMap<>();

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@
3737
*/
3838
public final class PainlessPlugin extends Plugin implements ScriptPlugin, ExtensiblePlugin {
3939

40-
// force to parse our definition at startup (not on the user's first script)
41-
static {
42-
Definition.DEFINITION.hashCode();
43-
}
44-
4540
@Override
4641
public ScriptEngine getScriptEngine(Settings settings, Collection<ScriptContext<?>> contexts) {
4742
return new PainlessScriptEngine(settings, contexts);

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

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,16 @@ public PainlessScriptEngine(Settings settings, Collection<ScriptContext<?>> cont
9999

100100
Map<ScriptContext<?>, Compiler> contextsToCompilers = new HashMap<>();
101101

102+
// Placeholder definition used for all contexts until SPI is fully integrated. Reduces memory foot print
103+
// by re-using the same definition since caching isn't implemented at this time.
104+
Definition definition = new Definition(
105+
Collections.singletonList(WhitelistLoader.loadFromResourceFiles(Definition.class, Definition.DEFINITION_FILES)));
106+
102107
for (ScriptContext<?> context : contexts) {
103108
if (context.instanceClazz.equals(SearchScript.class) || context.instanceClazz.equals(ExecutableScript.class)) {
104-
contextsToCompilers.put(context, new Compiler(GenericElasticsearchScript.class, Definition.DEFINITION));
109+
contextsToCompilers.put(context, new Compiler(GenericElasticsearchScript.class, definition));
105110
} else {
106-
contextsToCompilers.put(context, new Compiler(context.instanceClazz, Definition.DEFINITION));
111+
contextsToCompilers.put(context, new Compiler(context.instanceClazz, definition));
107112
}
108113
}
109114

@@ -126,9 +131,11 @@ public String getType() {
126131

127132
@Override
128133
public <T> T compile(String scriptName, String scriptSource, ScriptContext<T> context, Map<String, String> params) {
134+
Compiler compiler = contextsToCompilers.get(context);
135+
129136
if (context.instanceClazz.equals(SearchScript.class)) {
130137
GenericElasticsearchScript painlessScript =
131-
(GenericElasticsearchScript)compile(contextsToCompilers.get(context), scriptName, scriptSource, params);
138+
(GenericElasticsearchScript)compile(compiler, scriptName, scriptSource, params);
132139

133140
SearchScript.Factory factory = (p, lookup) -> new SearchScript.LeafFactory() {
134141
@Override
@@ -143,7 +150,7 @@ public boolean needs_score() {
143150
return context.factoryClazz.cast(factory);
144151
} else if (context.instanceClazz.equals(ExecutableScript.class)) {
145152
GenericElasticsearchScript painlessScript =
146-
(GenericElasticsearchScript)compile(contextsToCompilers.get(context), scriptName, scriptSource, params);
153+
(GenericElasticsearchScript)compile(compiler, scriptName, scriptSource, params);
147154

148155
ExecutableScript.Factory factory = (p) -> new ScriptImpl(painlessScript, p, null, null);
149156
return context.factoryClazz.cast(factory);
@@ -155,7 +162,7 @@ public boolean needs_score() {
155162
final Loader loader = AccessController.doPrivileged(new PrivilegedAction<Loader>() {
156163
@Override
157164
public Loader run() {
158-
return new Loader(getClass().getClassLoader());
165+
return compiler.createLoader(getClass().getClassLoader());
159166
}
160167
});
161168

@@ -414,7 +421,7 @@ Object compile(Compiler compiler, String scriptName, String source, Map<String,
414421
final Loader loader = AccessController.doPrivileged(new PrivilegedAction<Loader>() {
415422
@Override
416423
public Loader run() {
417-
return new Loader(getClass().getClassLoader());
424+
return compiler.createLoader(getClass().getClassLoader());
418425
}
419426
});
420427

modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java

Lines changed: 53 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -23,75 +23,82 @@
2323
import org.elasticsearch.painless.Definition.Type;
2424
import org.elasticsearch.test.ESTestCase;
2525

26+
import java.util.Collections;
27+
28+
import static org.elasticsearch.painless.Definition.DEFINITION_FILES;
29+
2630
public class AnalyzerCasterTests extends ESTestCase {
2731

32+
private static final Definition definition = new Definition(
33+
Collections.singletonList(WhitelistLoader.loadFromResourceFiles(Definition.class, DEFINITION_FILES)));
34+
2835
private static void assertCast(Type actual, Type expected, boolean mustBeExplicit) {
2936
Location location = new Location("dummy", 0);
3037

3138
if (actual.equals(expected)) {
3239
assertFalse(mustBeExplicit);
33-
assertNull(Definition.DEFINITION.caster.getLegalCast(location, actual, expected, false, false));
34-
assertNull(Definition.DEFINITION.caster.getLegalCast(location, actual, expected, true, false));
40+
assertNull(definition.caster.getLegalCast(location, actual, expected, false, false));
41+
assertNull(definition.caster.getLegalCast(location, actual, expected, true, false));
3542
return;
3643
}
3744

38-
Cast cast = Definition.DEFINITION.caster.getLegalCast(location, actual, expected, true, false);
45+
Cast cast = definition.caster.getLegalCast(location, actual, expected, true, false);
3946
assertEquals(actual, cast.from);
4047
assertEquals(expected, cast.to);
4148

4249
if (mustBeExplicit) {
4350
ClassCastException error = expectThrows(ClassCastException.class,
44-
() -> Definition.DEFINITION.caster.getLegalCast(location, actual, expected, false, false));
51+
() -> definition.caster.getLegalCast(location, actual, expected, false, false));
4552
assertTrue(error.getMessage().startsWith("Cannot cast"));
4653
} else {
47-
cast = Definition.DEFINITION.caster.getLegalCast(location, actual, expected, false, false);
54+
cast = definition.caster.getLegalCast(location, actual, expected, false, false);
4855
assertEquals(actual, cast.from);
4956
assertEquals(expected, cast.to);
5057
}
5158
}
5259

5360
public void testNumericCasts() {
54-
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.byteType, false);
55-
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.shortType, false);
56-
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.intType, false);
57-
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.longType, false);
58-
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.floatType, false);
59-
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.doubleType, false);
60-
61-
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.byteType, true);
62-
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.shortType, false);
63-
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.intType, false);
64-
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.longType, false);
65-
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.floatType, false);
66-
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.doubleType, false);
67-
68-
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.byteType, true);
69-
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.shortType, true);
70-
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.intType, false);
71-
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.longType, false);
72-
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.floatType, false);
73-
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.doubleType, false);
74-
75-
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.byteType, true);
76-
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.shortType, true);
77-
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.intType, true);
78-
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.longType, false);
79-
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.floatType, false);
80-
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.doubleType, false);
81-
82-
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.byteType, true);
83-
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.shortType, true);
84-
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.intType, true);
85-
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.longType, true);
86-
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.floatType, false);
87-
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.doubleType, false);
88-
89-
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.byteType, true);
90-
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.shortType, true);
91-
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.intType, true);
92-
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.longType, true);
93-
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.floatType, true);
94-
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.doubleType, false);
61+
assertCast(definition.byteType, definition.byteType, false);
62+
assertCast(definition.byteType, definition.shortType, false);
63+
assertCast(definition.byteType, definition.intType, false);
64+
assertCast(definition.byteType, definition.longType, false);
65+
assertCast(definition.byteType, definition.floatType, false);
66+
assertCast(definition.byteType, definition.doubleType, false);
67+
68+
assertCast(definition.shortType, definition.byteType, true);
69+
assertCast(definition.shortType, definition.shortType, false);
70+
assertCast(definition.shortType, definition.intType, false);
71+
assertCast(definition.shortType, definition.longType, false);
72+
assertCast(definition.shortType, definition.floatType, false);
73+
assertCast(definition.shortType, definition.doubleType, false);
74+
75+
assertCast(definition.intType, definition.byteType, true);
76+
assertCast(definition.intType, definition.shortType, true);
77+
assertCast(definition.intType, definition.intType, false);
78+
assertCast(definition.intType, definition.longType, false);
79+
assertCast(definition.intType, definition.floatType, false);
80+
assertCast(definition.intType, definition.doubleType, false);
81+
82+
assertCast(definition.longType, definition.byteType, true);
83+
assertCast(definition.longType, definition.shortType, true);
84+
assertCast(definition.longType, definition.intType, true);
85+
assertCast(definition.longType, definition.longType, false);
86+
assertCast(definition.longType, definition.floatType, false);
87+
assertCast(definition.longType, definition.doubleType, false);
88+
89+
assertCast(definition.floatType, definition.byteType, true);
90+
assertCast(definition.floatType, definition.shortType, true);
91+
assertCast(definition.floatType, definition.intType, true);
92+
assertCast(definition.floatType, definition.longType, true);
93+
assertCast(definition.floatType, definition.floatType, false);
94+
assertCast(definition.floatType, definition.doubleType, false);
95+
96+
assertCast(definition.doubleType, definition.byteType, true);
97+
assertCast(definition.doubleType, definition.shortType, true);
98+
assertCast(definition.doubleType, definition.intType, true);
99+
assertCast(definition.doubleType, definition.longType, true);
100+
assertCast(definition.doubleType, definition.floatType, true);
101+
assertCast(definition.doubleType, definition.doubleType, false);
95102
}
96103

97104
}

0 commit comments

Comments
 (0)