Skip to content

Commit d1e8a47

Browse files
authored
Separate ir tree generation from semantic checking (#59176)
This change creates a new phase to generate an ir tree once semantic checking is complete. The phase depends on the decorations generated during semantic checking against the user tree. Separation of the phases in this fashion will allow us to not generate an ir tree in the future when it's not necessary for features such as auto-completion or initial stored script compilation. While the change is long, the majority follows the pattern of removing the ir tree generation from each user tree node and instead adding it the UserTreeToIRTreeVisitor along with some new decorations to support this.
1 parent 60e0b46 commit d1e8a47

Some content is hidden

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

57 files changed

+2225
-1589
lines changed

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.elasticsearch.painless.ir.ClassNode;
2525
import org.elasticsearch.painless.lookup.PainlessLookup;
2626
import org.elasticsearch.painless.node.SClass;
27+
import org.elasticsearch.painless.phase.UserTreeToIRTreeVisitor;
2728
import org.elasticsearch.painless.spi.Whitelist;
2829
import org.elasticsearch.painless.symbol.ScriptScope;
2930
import org.objectweb.asm.util.Printer;
@@ -211,7 +212,8 @@ ScriptScope compile(Loader loader, String name, String source, CompilerSettings
211212
ScriptClassInfo scriptClassInfo = new ScriptClassInfo(painlessLookup, scriptClass);
212213
SClass root = Walker.buildPainlessTree(scriptClassInfo, scriptName, source, settings);
213214
ScriptScope scriptScope = new ScriptScope(painlessLookup, settings, scriptClassInfo, scriptName, source, root.getIdentifier() + 1);
214-
ClassNode classNode = root.analyze(scriptScope);
215+
root.analyze(scriptScope);
216+
ClassNode classNode = (ClassNode)new UserTreeToIRTreeVisitor().visitClass(root, scriptScope);
215217
DefBootstrapInjectionPhase.phase(classNode);
216218
ScriptInjectionPhase.phase(scriptScope, classNode);
217219
byte[] bytes = classNode.write();
@@ -241,7 +243,8 @@ byte[] compile(String name, String source, CompilerSettings settings, Printer de
241243
ScriptClassInfo scriptClassInfo = new ScriptClassInfo(painlessLookup, scriptClass);
242244
SClass root = Walker.buildPainlessTree(scriptClassInfo, scriptName, source, settings);
243245
ScriptScope scriptScope = new ScriptScope(painlessLookup, settings, scriptClassInfo, scriptName, source, root.getIdentifier() + 1);
244-
ClassNode classNode = root.analyze(scriptScope);
246+
root.analyze(scriptScope);
247+
ClassNode classNode = (ClassNode)new UserTreeToIRTreeVisitor().visitClass(root, scriptScope);
245248
classNode.setDebugStream(debugStream);
246249
DefBootstrapInjectionPhase.phase(classNode);
247250
ScriptInjectionPhase.phase(scriptScope, classNode);

modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@
113113
import org.elasticsearch.painless.node.AStatement;
114114
import org.elasticsearch.painless.node.EAssignment;
115115
import org.elasticsearch.painless.node.EBinary;
116-
import org.elasticsearch.painless.node.EBool;
117-
import org.elasticsearch.painless.node.EBoolean;
116+
import org.elasticsearch.painless.node.EBooleanComp;
117+
import org.elasticsearch.painless.node.EBooleanConstant;
118118
import org.elasticsearch.painless.node.EBrace;
119119
import org.elasticsearch.painless.node.ECall;
120120
import org.elasticsearch.painless.node.ECallLocal;
@@ -634,7 +634,7 @@ public ANode visitBool(BoolContext ctx) {
634634
throw location(ctx).createError(new IllegalStateException("illegal tree structure"));
635635
}
636636

637-
return new EBool(nextIdentifier(), location(ctx), left, right, operation);
637+
return new EBooleanComp(nextIdentifier(), location(ctx), left, right, operation);
638638
}
639639

640640
@Override
@@ -842,12 +842,12 @@ public ANode visitNumeric(NumericContext ctx) {
842842

843843
@Override
844844
public ANode visitTrue(TrueContext ctx) {
845-
return new EBoolean(nextIdentifier(), location(ctx), true);
845+
return new EBooleanConstant(nextIdentifier(), location(ctx), true);
846846
}
847847

848848
@Override
849849
public ANode visitFalse(FalseContext ctx) {
850-
return new EBoolean(nextIdentifier(), location(ctx), false);
850+
return new EBooleanConstant(nextIdentifier(), location(ctx), false);
851851
}
852852

853853
@Override

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
import org.elasticsearch.painless.MethodWriter;
2525
import org.elasticsearch.painless.ScriptClassInfo;
2626
import org.elasticsearch.painless.phase.IRTreeVisitor;
27-
import org.elasticsearch.painless.symbol.WriteScope;
2827
import org.elasticsearch.painless.symbol.ScriptScope;
28+
import org.elasticsearch.painless.symbol.WriteScope;
2929
import org.objectweb.asm.ClassVisitor;
3030
import org.objectweb.asm.Opcodes;
3131
import org.objectweb.asm.Type;

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

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,50 +22,28 @@
2222
import org.elasticsearch.painless.ClassWriter;
2323
import org.elasticsearch.painless.MethodWriter;
2424
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
25+
import org.elasticsearch.painless.lookup.def;
2526
import org.elasticsearch.painless.phase.IRTreeVisitor;
2627
import org.elasticsearch.painless.symbol.WriteScope;
27-
import org.objectweb.asm.Type;
2828

2929
public class InstanceofNode extends UnaryNode {
3030

3131
/* ---- begin node data ---- */
32-
32+
3333
private Class<?> instanceType;
34-
private Class<?> resolvedType;
35-
private boolean isPrimitiveResult;
3634

3735
public void setInstanceType(Class<?> instanceType) {
3836
this.instanceType = instanceType;
3937
}
40-
38+
4139
public Class<?> getInstanceType() {
4240
return instanceType;
4341
}
44-
42+
4543
public String getInstanceCanonicalTypeName() {
4644
return PainlessLookupUtility.typeToCanonicalTypeName(instanceType);
4745
}
4846

49-
public void setResolvedType(Class<?> resolvedType) {
50-
this.resolvedType = resolvedType;
51-
}
52-
53-
public Class<?> getResolvedType() {
54-
return resolvedType;
55-
}
56-
57-
public String getResolvedCanonicalTypeName() {
58-
return PainlessLookupUtility.typeToCanonicalTypeName(resolvedType);
59-
}
60-
61-
public void setPrimitiveResult(boolean isPrimitiveResult) {
62-
this.isPrimitiveResult = isPrimitiveResult;
63-
}
64-
65-
public boolean isPrimitiveResult() {
66-
return isPrimitiveResult;
67-
}
68-
6947
/* ---- end node data, begin visitor ---- */
7048

7149
@Override
@@ -79,15 +57,15 @@ public <Input, Output> Output visit(IRTreeVisitor<Input, Output> irTreeVisitor,
7957
protected void write(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
8058
getChildNode().write(classWriter, methodWriter, writeScope);
8159

82-
// primitive types
83-
if (isPrimitiveResult) {
84-
// discard child's result result
60+
if (instanceType == def.class) {
61+
methodWriter.writePop(MethodWriter.getType(getExpressionType()).getSize());
62+
methodWriter.push(true);
63+
} else if (getChildNode().getExpressionType().isPrimitive()) {
8564
methodWriter.writePop(MethodWriter.getType(getExpressionType()).getSize());
86-
// push our result: its' a primitive so it cannot be null
87-
methodWriter.push(resolvedType.isAssignableFrom(instanceType));
65+
methodWriter.push(PainlessLookupUtility.typeToBoxedType(instanceType).isAssignableFrom(
66+
PainlessLookupUtility.typeToBoxedType(getChildNode().getExpressionType())));
8867
} else {
89-
// ordinary instanceof
90-
methodWriter.instanceOf(Type.getType(resolvedType));
68+
methodWriter.instanceOf(MethodWriter.getType(PainlessLookupUtility.typeToBoxedType(instanceType)));
9169
}
9270
}
9371
}

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

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@
2121

2222
import org.elasticsearch.painless.AnalyzerCaster;
2323
import org.elasticsearch.painless.Location;
24-
import org.elasticsearch.painless.ir.CastNode;
25-
import org.elasticsearch.painless.ir.ClassNode;
26-
import org.elasticsearch.painless.ir.ExpressionNode;
2724
import org.elasticsearch.painless.lookup.PainlessCast;
2825
import org.elasticsearch.painless.symbol.Decorations.Explicit;
26+
import org.elasticsearch.painless.symbol.Decorations.ExpressionPainlessCast;
2927
import org.elasticsearch.painless.symbol.Decorations.Internal;
3028
import org.elasticsearch.painless.symbol.Decorations.PartialCanonicalTypeName;
3129
import org.elasticsearch.painless.symbol.Decorations.StaticType;
@@ -38,14 +36,6 @@
3836
*/
3937
public abstract class AExpression extends ANode {
4038

41-
public static class Output {
42-
43-
/**
44-
* The {@link ExpressionNode}(s) generated from this expression.
45-
*/
46-
ExpressionNode expressionNode = null;
47-
}
48-
4939
/**
5040
* Standard constructor with location used for error tracking.
5141
*/
@@ -56,16 +46,16 @@ public static class Output {
5646
/**
5747
* Checks for errors and collects data for the writing phase.
5848
*/
59-
Output analyze(ClassNode classNode, SemanticScope semanticScope) {
49+
void analyze(SemanticScope semanticScope) {
6050
throw new UnsupportedOperationException();
6151
}
6252

6353
/**
6454
* Checks for errors and collects data for the writing phase. Adds additional, common
6555
* error checking for conditions related to static types and partially constructed static types.
6656
*/
67-
static Output analyze(AExpression expression, ClassNode classNode, SemanticScope semanticScope) {
68-
Output output = expression.analyze(classNode, semanticScope);
57+
static void analyze(AExpression expression, SemanticScope semanticScope) {
58+
expression.analyze(semanticScope);
6959

7060
if (semanticScope.hasDecoration(expression, PartialCanonicalTypeName.class)) {
7161
throw expression.createError(new IllegalArgumentException("cannot resolve symbol " +
@@ -80,8 +70,6 @@ static Output analyze(AExpression expression, ClassNode classNode, SemanticScope
8070
if (semanticScope.hasDecoration(expression, ValueType.class) == false) {
8171
throw expression.createError(new IllegalStateException("value required: instead found no value"));
8272
}
83-
84-
return output;
8573
}
8674

8775
// TODO: move this somewhere more appropriate
@@ -91,20 +79,12 @@ public PainlessCast cast(SemanticScope semanticScope) {
9179
boolean isExplicitCast = semanticScope.getCondition(this, Explicit.class);
9280
boolean isInternalCast = semanticScope.getCondition(this, Internal.class);
9381

94-
return AnalyzerCaster.getLegalCast(getLocation(), valueType, targetType, isExplicitCast, isInternalCast);
95-
}
82+
PainlessCast painlessCast = AnalyzerCaster.getLegalCast(getLocation(), valueType, targetType, isExplicitCast, isInternalCast);
9683

97-
static ExpressionNode cast(ExpressionNode expressionNode, PainlessCast painlessCast) {
98-
if (painlessCast == null) {
99-
return expressionNode;
84+
if (painlessCast != null) {
85+
semanticScope.putDecoration(this, new ExpressionPainlessCast(painlessCast));
10086
}
10187

102-
CastNode castNode = new CastNode();
103-
castNode.setLocation(expressionNode.getLocation());
104-
castNode.setExpressionType(painlessCast.targetType);
105-
castNode.setCast(painlessCast);
106-
castNode.setChildNode(expressionNode);
107-
108-
return castNode;
88+
return painlessCast;
10989
}
11090
}

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

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

2222
import org.elasticsearch.painless.Location;
23-
import org.elasticsearch.painless.ir.ClassNode;
24-
import org.elasticsearch.painless.ir.StatementNode;
2523
import org.elasticsearch.painless.symbol.SemanticScope;
2624

2725
/**
2826
* The superclass for all S* (statement) nodes.
2927
*/
3028
public abstract class AStatement extends ANode {
3129

32-
public static class Output {
33-
34-
/**
35-
* The {@link StatementNode}(s) generated from this expression.
36-
*/
37-
StatementNode statementNode = null;
38-
}
39-
4030
/**
4131
* Standard constructor with location used for error tracking.
4232
*/
@@ -47,7 +37,7 @@ public static class Output {
4737
/**
4838
* Checks for errors and collects data for the writing phase.
4939
*/
50-
Output analyze(ClassNode classNode, SemanticScope semanticScope) {
40+
void analyze(SemanticScope semanticScope) {
5141
throw new UnsupportedOperationException();
5242
}
5343
}

0 commit comments

Comments
 (0)