Skip to content

Commit 01a07d4

Browse files
authored
Replace the Input/Output objects for the semantic phase with Decorations in Painless (#58506)
This change adds a decoration system for the phases used on the user tree. The Input and Output objects used during the semantic phase to support symbol existence, type checking, control flow checking, etc. are replaced by decorations on the "user" tree nodes instead. Two new classes are introduced for this - Decorator and Decorations. Decorator creates both a HashMap and HashSet for each node in the user tree as part of an array based on the user tree nodes' ids. (This avoids excessive hash lookups.) The HashMap contains decorations that require additional information such as types, while the HashSet contains conditions that are true if they exist within the HashSet and false, otherwise. (Many boolean conditions are set against the tree nodes during the semantic phase. This allows us to re-use condition objects instead of having to create a bunch of empty ones.) The decorations and conditions replace the data stored in the Input/Output objects. Decorations contains all the small classes that replace each of the variables in the Input/Output objects in a 1 to 1 mapping. The advantages of this decoration system are the following: * Strict decoupling of the data collected during the semantic phase from the user tree. * Allows us to split up the semantic phase into multiple phases easily. Each phase would have the expectation of using existing decorations from previous phases along with adding new decorations as more information is processed waling the tree. This means that we can add new phases easily for extensibility and split up the current semantic phase which does three separate things - gathering initial user function information, semantic validation, and creation of an IR tree. * Allows us to add new decorations/conditions easily for extensibility. This is particularly useful for adding new features outside of standard Painless moving forward. All the user tree nodes are updated to use this system, hence the larger change here. Other changes include renaming ScopeTable to WriteTable for the ir tree to avoid any confusion of what's used where, and removing statement counting from the loop counting where iterations is nearly the same and a lot simpler.
1 parent c9fc9c9 commit 01a07d4

File tree

114 files changed

+1900
-1455
lines changed

Some content is hidden

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

114 files changed

+1900
-1455
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ ScriptScope compile(Loader loader, String name, String source, CompilerSettings
210210
String scriptName = Location.computeSourceName(name);
211211
ScriptClassInfo scriptClassInfo = new ScriptClassInfo(painlessLookup, scriptClass);
212212
SClass root = Walker.buildPainlessTree(scriptClassInfo, scriptName, source, settings);
213-
ScriptScope scriptScope = new ScriptScope(painlessLookup, settings, scriptClassInfo, scriptName, source);
213+
ScriptScope scriptScope = new ScriptScope(painlessLookup, settings, scriptClassInfo, scriptName, source, root.getIdentifier() + 1);
214214
ClassNode classNode = root.analyze(scriptScope);
215215
DefBootstrapInjectionPhase.phase(classNode);
216216
ScriptInjectionPhase.phase(scriptScope, classNode);
@@ -240,7 +240,7 @@ byte[] compile(String name, String source, CompilerSettings settings, Printer de
240240
String scriptName = Location.computeSourceName(name);
241241
ScriptClassInfo scriptClassInfo = new ScriptClassInfo(painlessLookup, scriptClass);
242242
SClass root = Walker.buildPainlessTree(scriptClassInfo, scriptName, source, settings);
243-
ScriptScope scriptScope = new ScriptScope(painlessLookup, settings, scriptClassInfo, scriptName, source);
243+
ScriptScope scriptScope = new ScriptScope(painlessLookup, settings, scriptClassInfo, scriptName, source, root.getIdentifier() + 1);
244244
ClassNode classNode = root.analyze(scriptScope);
245245
classNode.setDebugStream(debugStream);
246246
DefBootstrapInjectionPhase.phase(classNode);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,12 @@ public void writeDebugInfo(Location location) {
143143
visitLineNumber(location.getOffset() + 1, label);
144144
}
145145

146-
public void writeLoopCounter(int slot, int count, Location location) {
146+
public void writeLoopCounter(int slot, Location location) {
147147
assert slot != -1;
148148
writeDebugInfo(location);
149149
final Label end = new Label();
150150

151-
iinc(slot, -count);
151+
iinc(slot, -1);
152152
visitVarInsn(Opcodes.ILOAD, slot);
153153
push(0);
154154
ifICmp(GeneratorAdapter.GT, end);

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import org.elasticsearch.painless.lookup.PainlessCast;
2828
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
2929
import org.elasticsearch.painless.lookup.def;
30-
import org.elasticsearch.painless.symbol.ScopeTable;
30+
import org.elasticsearch.painless.symbol.WriteScope;
3131

3232
public class AssignmentNode extends BinaryNode {
3333

@@ -104,7 +104,7 @@ public PainlessCast getBack() {
104104
/* ---- end node data ---- */
105105

106106
@Override
107-
protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
107+
protected void write(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
108108
methodWriter.writeDebugInfo(location);
109109

110110
// For the case where the assignment represents a String concatenation
@@ -119,18 +119,18 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTa
119119
}
120120

121121
// call the setup method on the lhs to prepare for a load/store operation
122-
getLeftNode().setup(classWriter, methodWriter, scopeTable);
122+
getLeftNode().setup(classWriter, methodWriter, writeScope);
123123

124124
if (cat) {
125125
// Handle the case where we are doing a compound assignment
126126
// representing a String concatenation.
127127

128128
methodWriter.writeDup(getLeftNode().accessElementCount(), catElementStackSize); // dup the top element and insert it
129129
// before concat helper on stack
130-
getLeftNode().load(classWriter, methodWriter, scopeTable); // read the current lhs's value
130+
getLeftNode().load(classWriter, methodWriter, writeScope); // read the current lhs's value
131131
methodWriter.writeAppendStrings(getLeftNode().getExpressionType()); // append the lhs's value using the StringBuilder
132132

133-
getRightNode().write(classWriter, methodWriter, scopeTable); // write the bytecode for the rhs
133+
getRightNode().write(classWriter, methodWriter, writeScope); // write the bytecode for the rhs
134134

135135
// check to see if the rhs has already done a concatenation
136136
if (getRightNode() instanceof BinaryMathNode == false || ((BinaryMathNode)getRightNode()).getCat() == false) {
@@ -148,15 +148,15 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTa
148148
}
149149

150150
// store the lhs's value from the stack in its respective variable/field/array
151-
getLeftNode().store(classWriter, methodWriter, scopeTable);
151+
getLeftNode().store(classWriter, methodWriter, writeScope);
152152
} else if (operation != null) {
153153
// Handle the case where we are doing a compound assignment that
154154
// does not represent a String concatenation.
155155

156156
methodWriter.writeDup(getLeftNode().accessElementCount(), 0); // if necessary, dup the previous lhs's value
157157
// to be both loaded from and stored to
158158

159-
getLeftNode().load(classWriter, methodWriter, scopeTable); // load the current lhs's value
159+
getLeftNode().load(classWriter, methodWriter, writeScope); // load the current lhs's value
160160

161161
if (read && post) {
162162
// dup the value if the lhs is also read from and is a post increment
@@ -167,7 +167,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTa
167167
methodWriter.writeCast(there); // if necessary cast the current lhs's value
168168
// to the promotion type between the lhs and rhs types
169169

170-
getRightNode().write(classWriter, methodWriter, scopeTable); // write the bytecode for the rhs
170+
getRightNode().write(classWriter, methodWriter, writeScope); // write the bytecode for the rhs
171171

172172
// XXX: fix these types, but first we need def compound assignment tests.
173173
// its tricky here as there are possibly explicit casts, too.
@@ -188,11 +188,11 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTa
188188
}
189189

190190
// store the lhs's value from the stack in its respective variable/field/array
191-
getLeftNode().store(classWriter, methodWriter, scopeTable);
191+
getLeftNode().store(classWriter, methodWriter, writeScope);
192192
} else {
193193
// Handle the case for a simple write.
194194

195-
getRightNode().write(classWriter, methodWriter, scopeTable); // write the bytecode for the rhs rhs
195+
getRightNode().write(classWriter, methodWriter, writeScope); // write the bytecode for the rhs rhs
196196

197197
if (read) {
198198
// dup the value if the lhs is also read from
@@ -201,7 +201,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTa
201201
}
202202

203203
// store the lhs's value from the stack in its respective variable/field/array
204-
getLeftNode().store(classWriter, methodWriter, scopeTable);
204+
getLeftNode().store(classWriter, methodWriter, writeScope);
205205
}
206206
}
207207
}

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import org.elasticsearch.painless.WriterConstants;
2828
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
2929
import org.elasticsearch.painless.lookup.def;
30-
import org.elasticsearch.painless.symbol.ScopeTable;
30+
import org.elasticsearch.painless.symbol.WriteScope;
3131

3232
import java.util.regex.Matcher;
3333
import java.util.regex.Pattern;
@@ -82,7 +82,7 @@ public boolean getCat() {
8282
return cat;
8383
}
8484

85-
public void setOriginallExplicit(boolean originallyExplicit) {
85+
public void setOriginallyExplicit(boolean originallyExplicit) {
8686
this.originallyExplicit = originallyExplicit;
8787
}
8888

@@ -98,21 +98,21 @@ public void setLocation(Location location) {
9898
/* ---- end node data ---- */
9999

100100
@Override
101-
protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
101+
protected void write(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
102102
methodWriter.writeDebugInfo(location);
103103

104104
if (getBinaryType() == String.class && operation == Operation.ADD) {
105105
if (cat == false) {
106106
methodWriter.writeNewStrings();
107107
}
108108

109-
getLeftNode().write(classWriter, methodWriter, scopeTable);
109+
getLeftNode().write(classWriter, methodWriter, writeScope);
110110

111111
if (getLeftNode() instanceof BinaryMathNode == false || ((BinaryMathNode)getLeftNode()).getCat() == false) {
112112
methodWriter.writeAppendStrings(getLeftNode().getExpressionType());
113113
}
114114

115-
getRightNode().write(classWriter, methodWriter, scopeTable);
115+
getRightNode().write(classWriter, methodWriter, writeScope);
116116

117117
if (getRightNode() instanceof BinaryMathNode == false || ((BinaryMathNode)getRightNode()).getCat() == false) {
118118
methodWriter.writeAppendStrings(getRightNode().getExpressionType());
@@ -122,8 +122,8 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTa
122122
methodWriter.writeToStrings();
123123
}
124124
} else if (operation == Operation.FIND || operation == Operation.MATCH) {
125-
getRightNode().write(classWriter, methodWriter, scopeTable);
126-
getLeftNode().write(classWriter, methodWriter, scopeTable);
125+
getRightNode().write(classWriter, methodWriter, writeScope);
126+
getLeftNode().write(classWriter, methodWriter, writeScope);
127127
methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_MATCHER);
128128

129129
if (operation == Operation.FIND) {
@@ -135,8 +135,8 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTa
135135
"for type [" + getExpressionCanonicalTypeName() + "]");
136136
}
137137
} else {
138-
getLeftNode().write(classWriter, methodWriter, scopeTable);
139-
getRightNode().write(classWriter, methodWriter, scopeTable);
138+
getLeftNode().write(classWriter, methodWriter, writeScope);
139+
getRightNode().write(classWriter, methodWriter, writeScope);
140140

141141
if (binaryType == def.class || (shiftType != null && shiftType == def.class)) {
142142
// def calls adopt the wanted return value. if there was a narrowing cast,

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
import org.elasticsearch.painless.ClassWriter;
2323
import org.elasticsearch.painless.MethodWriter;
24-
import org.elasticsearch.painless.symbol.ScopeTable;
24+
import org.elasticsearch.painless.symbol.WriteScope;
2525

2626
import java.util.ArrayList;
2727
import java.util.List;
@@ -64,11 +64,11 @@ public int getStatementCount() {
6464
/* ---- end node data ---- */
6565

6666
@Override
67-
protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
67+
protected void write(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
6868
for (StatementNode statementNode : statementNodes) {
6969
statementNode.continueLabel = continueLabel;
7070
statementNode.breakLabel = breakLabel;
71-
statementNode.write(classWriter, methodWriter, scopeTable);
71+
statementNode.write(classWriter, methodWriter, writeScope);
7272
}
7373
}
7474
}

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import org.elasticsearch.painless.ClassWriter;
2323
import org.elasticsearch.painless.MethodWriter;
2424
import org.elasticsearch.painless.Operation;
25-
import org.elasticsearch.painless.symbol.ScopeTable;
25+
import org.elasticsearch.painless.symbol.WriteScope;
2626
import org.objectweb.asm.Label;
2727
import org.objectweb.asm.Opcodes;
2828

@@ -43,16 +43,16 @@ public Operation getOperation() {
4343
/* ---- end node data ---- */
4444

4545
@Override
46-
protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
46+
protected void write(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
4747
methodWriter.writeDebugInfo(location);
4848

4949
if (operation == Operation.AND) {
5050
Label fals = new Label();
5151
Label end = new Label();
5252

53-
getLeftNode().write(classWriter, methodWriter, scopeTable);
53+
getLeftNode().write(classWriter, methodWriter, writeScope);
5454
methodWriter.ifZCmp(Opcodes.IFEQ, fals);
55-
getRightNode().write(classWriter, methodWriter, scopeTable);
55+
getRightNode().write(classWriter, methodWriter, writeScope);
5656
methodWriter.ifZCmp(Opcodes.IFEQ, fals);
5757

5858
methodWriter.push(true);
@@ -65,9 +65,9 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTa
6565
Label fals = new Label();
6666
Label end = new Label();
6767

68-
getLeftNode().write(classWriter, methodWriter, scopeTable);
68+
getLeftNode().write(classWriter, methodWriter, writeScope);
6969
methodWriter.ifZCmp(Opcodes.IFNE, tru);
70-
getRightNode().write(classWriter, methodWriter, scopeTable);
70+
getRightNode().write(classWriter, methodWriter, writeScope);
7171
methodWriter.ifZCmp(Opcodes.IFEQ, fals);
7272

7373
methodWriter.mark(tru);

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

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

2222
import org.elasticsearch.painless.ClassWriter;
2323
import org.elasticsearch.painless.MethodWriter;
24-
import org.elasticsearch.painless.symbol.ScopeTable;
24+
import org.elasticsearch.painless.symbol.WriteScope;
2525

2626
public class BraceNode extends BinaryNode {
2727

2828
@Override
29-
protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
30-
getLeftNode().write(classWriter, methodWriter, scopeTable);
31-
getRightNode().write(classWriter, methodWriter, scopeTable);
29+
protected void write(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
30+
getLeftNode().write(classWriter, methodWriter, writeScope);
31+
getRightNode().write(classWriter, methodWriter, writeScope);
3232
}
3333

3434
@Override
@@ -37,18 +37,18 @@ protected int accessElementCount() {
3737
}
3838

3939
@Override
40-
protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
41-
getLeftNode().write(classWriter, methodWriter, scopeTable);
42-
getRightNode().setup(classWriter, methodWriter, scopeTable);
40+
protected void setup(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
41+
getLeftNode().write(classWriter, methodWriter, writeScope);
42+
getRightNode().setup(classWriter, methodWriter, writeScope);
4343
}
4444

4545
@Override
46-
protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
47-
getRightNode().load(classWriter, methodWriter, scopeTable);
46+
protected void load(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
47+
getRightNode().load(classWriter, methodWriter, writeScope);
4848
}
4949

5050
@Override
51-
protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
52-
getRightNode().store(classWriter, methodWriter, scopeTable);
51+
protected void store(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
52+
getRightNode().store(classWriter, methodWriter, writeScope);
5353
}
5454
}

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@
2222
import org.elasticsearch.painless.ClassWriter;
2323
import org.elasticsearch.painless.DefBootstrap;
2424
import org.elasticsearch.painless.MethodWriter;
25-
import org.elasticsearch.painless.symbol.ScopeTable;
25+
import org.elasticsearch.painless.symbol.WriteScope;
2626
import org.objectweb.asm.Type;
2727

2828
public class BraceSubDefNode extends UnaryNode {
2929

3030
@Override
31-
protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
32-
setup(classWriter, methodWriter, scopeTable);
33-
load(classWriter, methodWriter, scopeTable);
31+
protected void write(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
32+
setup(classWriter, methodWriter, writeScope);
33+
load(classWriter, methodWriter, writeScope);
3434
}
3535

3636
@Override
@@ -39,16 +39,16 @@ protected int accessElementCount() {
3939
}
4040

4141
@Override
42-
protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
42+
protected void setup(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
4343
methodWriter.dup();
44-
getChildNode().write(classWriter, methodWriter, scopeTable);
44+
getChildNode().write(classWriter, methodWriter, writeScope);
4545
Type methodType = Type.getMethodType(MethodWriter.getType(
4646
getChildNode().getExpressionType()), Type.getType(Object.class), MethodWriter.getType(getChildNode().getExpressionType()));
4747
methodWriter.invokeDefCall("normalizeIndex", methodType, DefBootstrap.INDEX_NORMALIZE);
4848
}
4949

5050
@Override
51-
protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
51+
protected void load(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
5252
methodWriter.writeDebugInfo(location);
5353

5454
Type methodType = Type.getMethodType(MethodWriter.getType(
@@ -57,7 +57,7 @@ protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTab
5757
}
5858

5959
@Override
60-
protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
60+
protected void store(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
6161
methodWriter.writeDebugInfo(location);
6262

6363
Type methodType = Type.getMethodType(Type.getType(void.class), Type.getType(Object.class),

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

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

2222
import org.elasticsearch.painless.ClassWriter;
2323
import org.elasticsearch.painless.MethodWriter;
24-
import org.elasticsearch.painless.symbol.ScopeTable;
24+
import org.elasticsearch.painless.symbol.WriteScope;
2525
import org.objectweb.asm.Label;
2626
import org.objectweb.asm.Opcodes;
2727

2828
public class BraceSubNode extends UnaryNode {
2929

3030
@Override
31-
protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
32-
setup(classWriter, methodWriter, scopeTable);
33-
load(classWriter, methodWriter, scopeTable);
31+
protected void write(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
32+
setup(classWriter, methodWriter, writeScope);
33+
load(classWriter, methodWriter, writeScope);
3434
}
3535

3636
@Override
@@ -39,8 +39,8 @@ protected int accessElementCount() {
3939
}
4040

4141
@Override
42-
protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
43-
getChildNode().write(classWriter, methodWriter, scopeTable);
42+
protected void setup(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
43+
getChildNode().write(classWriter, methodWriter, writeScope);
4444

4545
Label noFlip = new Label();
4646
methodWriter.dup();
@@ -53,13 +53,13 @@ protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTa
5353
}
5454

5555
@Override
56-
protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
56+
protected void load(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
5757
methodWriter.writeDebugInfo(location);
5858
methodWriter.arrayLoad(MethodWriter.getType(getExpressionType()));
5959
}
6060

6161
@Override
62-
protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
62+
protected void store(ClassWriter classWriter, MethodWriter methodWriter, WriteScope writeScope) {
6363
methodWriter.writeDebugInfo(location);
6464
methodWriter.arrayStore(MethodWriter.getType(getExpressionType()));
6565
}

0 commit comments

Comments
 (0)