Skip to content

Commit c3767b1

Browse files
authored
Remove "extractVariables" phase from Painless user tree (#51690)
Removes the "extractVariables" phase from the Painless user tree which is no longer necessary. The information to retrieve used variables is now collected during the semantic ("analysis") phase and passed back through ScriptRoot to generate the appropriate needs methods in the factories.
1 parent 715d5eb commit c3767b1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+88
-611
lines changed

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

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@
3636
import java.security.cert.Certificate;
3737
import java.util.Collections;
3838
import java.util.HashMap;
39-
import java.util.HashSet;
4039
import java.util.Map;
41-
import java.util.Set;
4240
import java.util.concurrent.atomic.AtomicInteger;
4341

4442
import static org.elasticsearch.painless.WriterConstants.CLASS_NAME;
@@ -208,11 +206,9 @@ private static void addFactoryMethod(Map<String, Class<?>> additionalClasses, Cl
208206
* @param settings The CompilerSettings to be used during the compilation.
209207
* @return The ScriptRoot used to compile
210208
*/
211-
ScriptRoot compile(Loader loader, Set<String> extractedVariables, String name, String source,
212-
CompilerSettings settings) {
209+
ScriptRoot compile(Loader loader, String name, String source, CompilerSettings settings) {
213210
ScriptClassInfo scriptClassInfo = new ScriptClassInfo(painlessLookup, scriptClass);
214211
SClass root = Walker.buildPainlessTree(scriptClassInfo, name, source, settings, painlessLookup, null);
215-
root.extractVariables(extractedVariables);
216212
ScriptRoot scriptRoot = root.analyze(painlessLookup, settings);
217213
ClassNode classNode = root.writeClass();
218214
Map<String, Object> statics = classNode.write();
@@ -243,9 +239,7 @@ ScriptRoot compile(Loader loader, Set<String> extractedVariables, String name, S
243239
*/
244240
byte[] compile(String name, String source, CompilerSettings settings, Printer debugStream) {
245241
ScriptClassInfo scriptClassInfo = new ScriptClassInfo(painlessLookup, scriptClass);
246-
SClass root = Walker.buildPainlessTree(scriptClassInfo, name, source, settings, painlessLookup,
247-
debugStream);
248-
root.extractVariables(new HashSet<>());
242+
SClass root = Walker.buildPainlessTree(scriptClassInfo, name, source, settings, painlessLookup, debugStream);
249243
root.analyze(painlessLookup, settings);
250244
ClassNode classNode = root.writeClass();
251245
classNode.write();

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

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import java.util.Arrays;
4646
import java.util.Collections;
4747
import java.util.HashMap;
48-
import java.util.HashSet;
4948
import java.util.List;
5049
import java.util.Map;
5150
import java.util.Set;
@@ -142,14 +141,12 @@ public Loader run() {
142141
}
143142
});
144143

145-
Set<String> extractedVariables = new HashSet<>();
146-
ScriptRoot scriptRoot = compile(contextsToCompilers.get(context), loader, extractedVariables, scriptName, scriptSource, params);
144+
ScriptRoot scriptRoot = compile(contextsToCompilers.get(context), loader, scriptName, scriptSource, params);
147145

148146
if (context.statefulFactoryClazz != null) {
149-
return generateFactory(loader, context, extractedVariables, generateStatefulFactory(loader, context, extractedVariables),
150-
scriptRoot);
147+
return generateFactory(loader, context, generateStatefulFactory(loader, context, scriptRoot), scriptRoot);
151148
} else {
152-
return generateFactory(loader, context, extractedVariables, WriterConstants.CLASS_TYPE, scriptRoot);
149+
return generateFactory(loader, context, WriterConstants.CLASS_TYPE, scriptRoot);
153150
}
154151
}
155152

@@ -172,7 +169,7 @@ public Set<ScriptContext<?>> getSupportedContexts() {
172169
private <T> Type generateStatefulFactory(
173170
Loader loader,
174171
ScriptContext<T> context,
175-
Set<String> extractedVariables
172+
ScriptRoot scriptRoot
176173
) {
177174
int classFrames = ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS;
178175
int classAccess = Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER | Opcodes.ACC_FINAL;
@@ -254,7 +251,7 @@ private <T> Type generateStatefulFactory(
254251
adapter.returnValue();
255252
adapter.endMethod();
256253

257-
writeNeedsMethods(context.statefulFactoryClazz, writer, extractedVariables);
254+
writeNeedsMethods(context.statefulFactoryClazz, writer, scriptRoot.getUsedVariables());
258255
writer.visitEnd();
259256

260257
loader.defineFactory(className.replace('/', '.'), writer.toByteArray());
@@ -278,7 +275,6 @@ private <T> Type generateStatefulFactory(
278275
private <T> T generateFactory(
279276
Loader loader,
280277
ScriptContext<T> context,
281-
Set<String> extractedVariables,
282278
Type classType,
283279
ScriptRoot scriptRoot
284280
) {
@@ -332,7 +328,7 @@ private <T> T generateFactory(
332328
adapter.returnValue();
333329
adapter.endMethod();
334330

335-
writeNeedsMethods(context.factoryClazz, writer, extractedVariables);
331+
writeNeedsMethods(context.factoryClazz, writer, scriptRoot.getUsedVariables());
336332

337333
String methodName = "isResultDeterministic";
338334
org.objectweb.asm.commons.Method isResultDeterministic = new org.objectweb.asm.commons.Method(methodName,
@@ -378,8 +374,7 @@ private void writeNeedsMethods(Class<?> clazz, ClassWriter writer, Set<String> e
378374
}
379375
}
380376

381-
ScriptRoot compile(Compiler compiler, Loader loader, Set<String> extractedVariables,
382-
String scriptName, String source, Map<String, String> params) {
377+
ScriptRoot compile(Compiler compiler, Loader loader, String scriptName, String source, Map<String, String> params) {
383378
final CompilerSettings compilerSettings = buildCompilerSettings(params);
384379

385380
try {
@@ -388,7 +383,7 @@ ScriptRoot compile(Compiler compiler, Loader loader, Set<String> extractedVariab
388383
@Override
389384
public ScriptRoot run() {
390385
String name = scriptName == null ? source : scriptName;
391-
return compiler.compile(loader, extractedVariables, name, source, compilerSettings);
386+
return compiler.compile(loader, name, source, compilerSettings);
392387
}
393388
}, COMPILATION_CONTEXT);
394389
// Note that it is safe to catch any of the following errors since Painless is stateless.

modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,8 @@
4141
import java.util.BitSet;
4242
import java.util.Collection;
4343
import java.util.HashMap;
44-
import java.util.HashSet;
4544
import java.util.List;
4645
import java.util.Map;
47-
import java.util.Set;
4846

4947
import static org.elasticsearch.painless.WriterConstants.BASE_INTERFACE_TYPE;
5048
import static org.elasticsearch.painless.WriterConstants.BITSET_TYPE;
@@ -109,7 +107,6 @@ public List<StatementNode> getStatementsNodes() {
109107
private Printer debugStream;
110108
private ScriptRoot scriptRoot;
111109
private boolean doesMethodEscape;
112-
private final Set<String> extractedVariables = new HashSet<>();
113110

114111
public void setScriptClassInfo(ScriptClassInfo scriptClassInfo) {
115112
this.scriptClassInfo = scriptClassInfo;
@@ -159,18 +156,6 @@ public boolean doesMethodEscape() {
159156
return doesMethodEscape;
160157
}
161158

162-
public void addExtractedVariable(String extractedVariable) {
163-
extractedVariables.add(extractedVariable);
164-
}
165-
166-
public boolean containsExtractedVariable(String extractedVariable) {
167-
return extractedVariables.contains(extractedVariable);
168-
}
169-
170-
public Set<String> getExtractedVariables() {
171-
return extractedVariables;
172-
}
173-
174159
/* ---- end node data ---- */
175160

176161
protected Globals globals;
@@ -299,7 +284,7 @@ public Map<String, Object> write() {
299284
name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
300285
MethodWriter ifaceMethod = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, needsMethod);
301286
ifaceMethod.visitCode();
302-
ifaceMethod.push(extractedVariables.contains(name));
287+
ifaceMethod.push(scriptRoot.getUsedVariables().contains(name));
303288
ifaceMethod.returnValue();
304289
ifaceMethod.endMethod();
305290
}
@@ -355,7 +340,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals
355340
String name = method.getName().substring(3);
356341
name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
357342

358-
if (extractedVariables.contains(name)) {
343+
if (scriptRoot.getUsedVariables().contains(name)) {
359344
Variable variable = scopeTable.defineVariable(returnType, name);
360345

361346
methodWriter.loadThis();

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
package org.elasticsearch.painless.node;
2121

2222
import org.elasticsearch.painless.AnalyzerCaster;
23-
import org.elasticsearch.painless.Scope;
2423
import org.elasticsearch.painless.Location;
24+
import org.elasticsearch.painless.Scope;
2525
import org.elasticsearch.painless.ir.ClassNode;
2626
import org.elasticsearch.painless.ir.ExpressionNode;
2727
import org.elasticsearch.painless.lookup.PainlessCast;

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import java.util.Iterator;
3131
import java.util.List;
3232
import java.util.Objects;
33-
import java.util.Set;
3433

3534
import static java.lang.Math.max;
3635
import static java.util.Collections.emptyList;
@@ -52,14 +51,6 @@ public abstract class ANode {
5251
this.location = Objects.requireNonNull(location);
5352
}
5453

55-
/**
56-
* Adds all variable names referenced to the variable set.
57-
* <p>
58-
* This can be called at any time, e.g. to support lambda capture.
59-
* @param variables set of variables referenced (any scope)
60-
*/
61-
abstract void extractVariables(Set<String> variables);
62-
6354
/**
6455
* Writes ASM based on the data collected during the analysis phase.
6556
* @param classNode the root {@link ClassNode}

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121

2222

2323
import org.elasticsearch.painless.AnalyzerCaster;
24-
import org.elasticsearch.painless.Scope;
2524
import org.elasticsearch.painless.Location;
2625
import org.elasticsearch.painless.Operation;
26+
import org.elasticsearch.painless.Scope;
2727
import org.elasticsearch.painless.ir.AssignmentNode;
2828
import org.elasticsearch.painless.ir.ClassNode;
2929
import org.elasticsearch.painless.lookup.PainlessCast;
@@ -33,7 +33,6 @@
3333
import java.util.ArrayList;
3434
import java.util.List;
3535
import java.util.Objects;
36-
import java.util.Set;
3736

3837
/**
3938
* Represents an assignment with the lhs and rhs as child nodes.
@@ -62,15 +61,6 @@ public EAssignment(Location location, AExpression lhs, AExpression rhs, boolean
6261
this.operation = operation;
6362
}
6463

65-
@Override
66-
void extractVariables(Set<String> variables) {
67-
lhs.extractVariables(variables);
68-
69-
if (rhs != null) {
70-
rhs.extractVariables(variables);
71-
}
72-
}
73-
7464
@Override
7565
void analyze(ScriptRoot scriptRoot, Scope scope) {
7666
analyzeLHS(scriptRoot, scope);

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,16 @@
2020
package org.elasticsearch.painless.node;
2121

2222
import org.elasticsearch.painless.AnalyzerCaster;
23-
import org.elasticsearch.painless.Scope;
2423
import org.elasticsearch.painless.Location;
2524
import org.elasticsearch.painless.Operation;
25+
import org.elasticsearch.painless.Scope;
2626
import org.elasticsearch.painless.ir.BinaryMathNode;
2727
import org.elasticsearch.painless.ir.ClassNode;
2828
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
2929
import org.elasticsearch.painless.lookup.def;
3030
import org.elasticsearch.painless.symbol.ScriptRoot;
3131

3232
import java.util.Objects;
33-
import java.util.Set;
3433
import java.util.regex.Pattern;
3534

3635
/**
@@ -55,12 +54,6 @@ public EBinary(Location location, Operation operation, AExpression left, AExpres
5554
this.right = Objects.requireNonNull(right);
5655
}
5756

58-
@Override
59-
void extractVariables(Set<String> variables) {
60-
left.extractVariables(variables);
61-
right.extractVariables(variables);
62-
}
63-
6457
@Override
6558
void analyze(ScriptRoot scriptRoot, Scope scope) {
6659
originallyExplicit = explicit;

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,14 @@
1919

2020
package org.elasticsearch.painless.node;
2121

22-
import org.elasticsearch.painless.Scope;
2322
import org.elasticsearch.painless.Location;
2423
import org.elasticsearch.painless.Operation;
24+
import org.elasticsearch.painless.Scope;
2525
import org.elasticsearch.painless.ir.BooleanNode;
2626
import org.elasticsearch.painless.ir.ClassNode;
2727
import org.elasticsearch.painless.symbol.ScriptRoot;
2828

2929
import java.util.Objects;
30-
import java.util.Set;
3130

3231
/**
3332
* Represents a boolean expression.
@@ -46,12 +45,6 @@ public EBool(Location location, Operation operation, AExpression left, AExpressi
4645
this.right = Objects.requireNonNull(right);
4746
}
4847

49-
@Override
50-
void extractVariables(Set<String> variables) {
51-
left.extractVariables(variables);
52-
right.extractVariables(variables);
53-
}
54-
5548
@Override
5649
void analyze(ScriptRoot scriptRoot, Scope scope) {
5750
left.expected = boolean.class;

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,12 @@
1919

2020
package org.elasticsearch.painless.node;
2121

22-
import org.elasticsearch.painless.Scope;
2322
import org.elasticsearch.painless.Location;
23+
import org.elasticsearch.painless.Scope;
2424
import org.elasticsearch.painless.ir.ClassNode;
2525
import org.elasticsearch.painless.ir.ExpressionNode;
2626
import org.elasticsearch.painless.symbol.ScriptRoot;
2727

28-
import java.util.Set;
29-
3028
/**
3129
* Represents a boolean constant.
3230
*/
@@ -38,11 +36,6 @@ public EBoolean(Location location, boolean constant) {
3836
this.constant = constant;
3937
}
4038

41-
@Override
42-
void extractVariables(Set<String> variables) {
43-
// Do nothing.
44-
}
45-
4639
@Override
4740
void analyze(ScriptRoot scriptRoot, Scope scope) {
4841
if (!read) {

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919

2020
package org.elasticsearch.painless.node;
2121

22-
import org.elasticsearch.painless.Scope;
2322
import org.elasticsearch.painless.Location;
23+
import org.elasticsearch.painless.Scope;
2424
import org.elasticsearch.painless.ir.ClassNode;
2525
import org.elasticsearch.painless.ir.UnboundCallNode;
2626
import org.elasticsearch.painless.lookup.PainlessClassBinding;
@@ -34,7 +34,6 @@
3434
import java.util.ArrayList;
3535
import java.util.List;
3636
import java.util.Objects;
37-
import java.util.Set;
3837

3938
/**
4039
* Represents a user-defined call.
@@ -58,13 +57,6 @@ public ECallLocal(Location location, String name, List<AExpression> arguments) {
5857
this.arguments = Objects.requireNonNull(arguments);
5958
}
6059

61-
@Override
62-
void extractVariables(Set<String> variables) {
63-
for (AExpression argument : arguments) {
64-
argument.extractVariables(variables);
65-
}
66-
}
67-
6860
@Override
6961
void analyze(ScriptRoot scriptRoot, Scope scope) {
7062
localFunction = scriptRoot.getFunctionTable().getFunction(name, arguments.size());

0 commit comments

Comments
 (0)