From 9d2c5796367afa8af25eeed08cf38390ebbfcae6 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 28 Jan 2020 12:29:21 -0800 Subject: [PATCH] Move variable slotting to the IR tree (#51452) Currently, variable slotting (a variable's index on the ASM stack) is generated by the user tree during semantic checking. With the split it no longer makes sense to have the user tree generate a variable's slot. This PR moves variable slot allocation to the IR tree using the class ScopeTable. This class holds variables currently in scope and calculates an appropriate slot for them. This also allows for optimization phases to occur on the IR tree because now variables can be injected without having to update slotting. --- .../painless/ir/AssignmentNode.java | 22 ++-- .../painless/ir/BinaryMathNode.java | 15 +-- .../elasticsearch/painless/ir/BlockNode.java | 5 +- .../painless/ir/BooleanNode.java | 11 +- .../elasticsearch/painless/ir/BraceNode.java | 21 ++-- .../painless/ir/BraceSubDefNode.java | 15 +-- .../painless/ir/BraceSubNode.java | 15 +-- .../elasticsearch/painless/ir/BreakNode.java | 3 +- .../elasticsearch/painless/ir/CallNode.java | 7 +- .../painless/ir/CallSubDefNode.java | 5 +- .../painless/ir/CallSubNode.java | 5 +- .../painless/ir/CapturingFuncRefNode.java | 24 ++-- .../elasticsearch/painless/ir/CastNode.java | 5 +- .../elasticsearch/painless/ir/CatchNode.java | 15 ++- .../elasticsearch/painless/ir/ClassNode.java | 54 ++++---- .../painless/ir/ComparisonNode.java | 7 +- .../painless/ir/ConditionalNode.java | 9 +- .../painless/ir/ConstantNode.java | 3 +- .../painless/ir/ContinueNode.java | 3 +- .../painless/ir/DeclarationBlockNode.java | 5 +- .../painless/ir/DeclarationNode.java | 37 ++++-- .../painless/ir/DoWhileLoopNode.java | 16 ++- .../elasticsearch/painless/ir/DotNode.java | 22 ++-- .../painless/ir/DotSubArrayLengthNode.java | 3 +- .../painless/ir/DotSubDefNode.java | 9 +- .../elasticsearch/painless/ir/DotSubNode.java | 9 +- .../painless/ir/DotSubShortcutNode.java | 9 +- .../elasticsearch/painless/ir/ElvisNode.java | 7 +- .../elasticsearch/painless/ir/FieldNode.java | 3 +- .../painless/ir/ForEachLoopNode.java | 6 +- .../painless/ir/ForEachSubArrayNode.java | 108 +++++++++++----- .../painless/ir/ForEachSubIterableNode.java | 64 +++++++--- .../painless/ir/ForLoopNode.java | 33 +++-- .../painless/ir/FuncRefNode.java | 3 +- .../painless/ir/FunctionNode.java | 37 +++--- .../org/elasticsearch/painless/ir/IRNode.java | 24 +++- .../elasticsearch/painless/ir/IfElseNode.java | 9 +- .../org/elasticsearch/painless/ir/IfNode.java | 7 +- .../painless/ir/InstanceofNode.java | 5 +- .../elasticsearch/painless/ir/LambdaNode.java | 21 ++-- .../painless/ir/ListInitializationNode.java | 5 +- .../painless/ir/ListSubShortcutNode.java | 15 +-- .../elasticsearch/painless/ir/LoopNode.java | 11 -- .../painless/ir/MapInitializationNode.java | 7 +- .../painless/ir/MapSubShortcutNode.java | 13 +- .../painless/ir/NewArrayFuncRefNode.java | 3 +- .../painless/ir/NewArrayNode.java | 7 +- .../painless/ir/NewObjectNode.java | 5 +- .../elasticsearch/painless/ir/NullNode.java | 3 +- .../painless/ir/NullSafeSubNode.java | 5 +- .../elasticsearch/painless/ir/RegexNode.java | 3 +- .../elasticsearch/painless/ir/ReturnNode.java | 5 +- .../painless/ir/StatementExpressionNode.java | 5 +- .../elasticsearch/painless/ir/StaticNode.java | 3 +- .../elasticsearch/painless/ir/ThrowNode.java | 5 +- .../elasticsearch/painless/ir/TryNode.java | 7 +- .../painless/ir/UnaryMathNode.java | 7 +- .../painless/ir/UnboundCallNode.java | 13 +- .../painless/ir/VariableNode.java | 30 +++-- .../elasticsearch/painless/ir/WhileNode.java | 22 ++-- .../painless/node/ECapturingFunctionRef.java | 3 +- .../elasticsearch/painless/node/ELambda.java | 5 +- .../painless/node/EVariable.java | 2 +- .../elasticsearch/painless/node/SClass.java | 4 - .../painless/node/SDeclaration.java | 6 +- .../org/elasticsearch/painless/node/SDo.java | 1 - .../org/elasticsearch/painless/node/SFor.java | 1 - .../painless/node/SFunction.java | 2 +- .../painless/node/SSubEachArray.java | 10 +- .../painless/node/SSubEachIterable.java | 7 +- .../elasticsearch/painless/node/SWhile.java | 1 - .../painless/symbol/ScopeTable.java | 118 ++++++++++++++++++ 72 files changed, 655 insertions(+), 360 deletions(-) create mode 100644 modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScopeTable.java diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java index 8841143e84d53..4499a9f1f490e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java @@ -28,6 +28,7 @@ import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; +import org.elasticsearch.painless.symbol.ScopeTable; public class AssignmentNode extends BinaryNode { @@ -113,7 +114,7 @@ public PainlessCast getBack() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); // For the case where the assignment represents a String concatenation @@ -127,7 +128,8 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals catElementStackSize = methodWriter.writeNewStrings(); } - getLeftNode().setup(classWriter, methodWriter, globals); // call the setup method on the lhs to prepare for a load/store operation + // call the setup method on the lhs to prepare for a load/store operation + getLeftNode().setup(classWriter, methodWriter, globals, scopeTable); if (cat) { // Handle the case where we are doing a compound assignment @@ -135,10 +137,10 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.writeDup(getLeftNode().accessElementCount(), catElementStackSize); // dup the top element and insert it // before concat helper on stack - getLeftNode().load(classWriter, methodWriter, globals); // read the current lhs's value + getLeftNode().load(classWriter, methodWriter, globals, scopeTable); // read the current lhs's value methodWriter.writeAppendStrings(getLeftNode().getExpressionType()); // append the lhs's value using the StringBuilder - getRightNode().write(classWriter, methodWriter, globals); // write the bytecode for the rhs + getRightNode().write(classWriter, methodWriter, globals, scopeTable); // write the bytecode for the rhs // check to see if the rhs has already done a concatenation if (getRightNode() instanceof BinaryMathNode == false || ((BinaryMathNode)getRightNode()).getCat() == false) { @@ -156,14 +158,14 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals } // store the lhs's value from the stack in its respective variable/field/array - getLeftNode().store(classWriter, methodWriter, globals); + getLeftNode().store(classWriter, methodWriter, globals, scopeTable); } else if (operation != null) { // Handle the case where we are doing a compound assignment that // does not represent a String concatenation. methodWriter.writeDup(getLeftNode().accessElementCount(), 0); // if necessary, dup the previous lhs's value // to be both loaded from and stored to - getLeftNode().load(classWriter, methodWriter, globals); // load the current lhs's value + getLeftNode().load(classWriter, methodWriter, globals, scopeTable); // load the current lhs's value if (read && post) { // dup the value if the lhs is also read from and is a post increment @@ -173,7 +175,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.writeCast(there); // if necessary cast the current lhs's value // to the promotion type between the lhs and rhs types - getRightNode().write(classWriter, methodWriter, globals); // write the bytecode for the rhs + getRightNode().write(classWriter, methodWriter, globals, scopeTable); // write the bytecode for the rhs // XXX: fix these types, but first we need def compound assignment tests. // its tricky here as there are possibly explicit casts, too. @@ -194,11 +196,11 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals } // store the lhs's value from the stack in its respective variable/field/array - getLeftNode().store(classWriter, methodWriter, globals); + getLeftNode().store(classWriter, methodWriter, globals, scopeTable); } else { // Handle the case for a simple write. - getRightNode().write(classWriter, methodWriter, globals); // write the bytecode for the rhs rhs + getRightNode().write(classWriter, methodWriter, globals, scopeTable); // write the bytecode for the rhs rhs if (read) { // dup the value if the lhs is also read from @@ -207,7 +209,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals } // store the lhs's value from the stack in its respective variable/field/array - getLeftNode().store(classWriter, methodWriter, globals); + getLeftNode().store(classWriter, methodWriter, globals, scopeTable); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java index cff2f89c3a676..cddb42dcee6e0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java @@ -28,6 +28,7 @@ import org.elasticsearch.painless.WriterConstants; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; +import org.elasticsearch.painless.symbol.ScopeTable; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -98,7 +99,7 @@ public void setLocation(Location location) { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); if (getBinaryType() == String.class && operation == Operation.ADD) { @@ -106,13 +107,13 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.writeNewStrings(); } - getLeftNode().write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); if (getLeftNode() instanceof BinaryMathNode == false || ((BinaryMathNode)getLeftNode()).getCat() == false) { methodWriter.writeAppendStrings(getLeftNode().getExpressionType()); } - getRightNode().write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals, scopeTable); if (getRightNode() instanceof BinaryMathNode == false || ((BinaryMathNode)getRightNode()).getCat() == false) { methodWriter.writeAppendStrings(getRightNode().getExpressionType()); @@ -122,8 +123,8 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.writeToStrings(); } } else if (operation == Operation.FIND || operation == Operation.MATCH) { - getRightNode().write(classWriter, methodWriter, globals); - getLeftNode().write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals, scopeTable); + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_MATCHER); if (operation == Operation.FIND) { @@ -135,8 +136,8 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals "for type [" + getExpressionCanonicalTypeName() + "]"); } } else { - getLeftNode().write(classWriter, methodWriter, globals); - getRightNode().write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); + getRightNode().write(classWriter, methodWriter, globals, scopeTable); if (binaryType == def.class || (shiftType != null && shiftType == def.class)) { // def calls adopt the wanted return value. if there was a narrowing cast, diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java index fdc0c3e32530c..65bc2adc118ab 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import java.util.ArrayList; import java.util.List; @@ -64,11 +65,11 @@ public int getStatementCount() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { for (StatementNode statementNode : statementNodes) { statementNode.continueLabel = continueLabel; statementNode.breakLabel = breakLabel; - statementNode.write(classWriter, methodWriter, globals); + statementNode.write(classWriter, methodWriter, globals, scopeTable); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java index 65057de255fe9..2d2ab280e38c8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -43,16 +44,16 @@ public Operation getOperation() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); if (operation == Operation.AND) { Label fals = new Label(); Label end = new Label(); - getLeftNode().write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.ifZCmp(Opcodes.IFEQ, fals); - getRightNode().write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.ifZCmp(Opcodes.IFEQ, fals); methodWriter.push(true); @@ -65,9 +66,9 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals Label fals = new Label(); Label end = new Label(); - getLeftNode().write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.ifZCmp(Opcodes.IFNE, tru); - getRightNode().write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.ifZCmp(Opcodes.IFEQ, fals); methodWriter.mark(tru); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java index 4a3dea6778622..dbc6f7cd95779 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java @@ -22,13 +22,14 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class BraceNode extends BinaryNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getLeftNode().write(classWriter, methodWriter, globals); - getRightNode().write(classWriter, methodWriter, globals); + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); + getRightNode().write(classWriter, methodWriter, globals, scopeTable); } @Override @@ -37,18 +38,18 @@ protected int accessElementCount() { } @Override - protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getLeftNode().write(classWriter, methodWriter, globals); - getRightNode().setup(classWriter, methodWriter, globals); + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); + getRightNode().setup(classWriter, methodWriter, globals, scopeTable); } @Override - protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getRightNode().load(classWriter, methodWriter, globals); + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getRightNode().load(classWriter, methodWriter, globals, scopeTable); } @Override - protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getRightNode().store(classWriter, methodWriter, globals); + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getRightNode().store(classWriter, methodWriter, globals, scopeTable); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java index 2be964e9967d2..ebb99785106cb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java @@ -23,14 +23,15 @@ import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Type; public class BraceSubDefNode extends UnaryNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - setup(classWriter, methodWriter, globals); - load(classWriter, methodWriter, globals); + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + setup(classWriter, methodWriter, globals, scopeTable); + load(classWriter, methodWriter, globals, scopeTable); } @Override @@ -39,16 +40,16 @@ protected int accessElementCount() { } @Override - protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.dup(); - getChildNode().write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals, scopeTable); Type methodType = Type.getMethodType(MethodWriter.getType( getChildNode().getExpressionType()), Type.getType(Object.class), MethodWriter.getType(getChildNode().getExpressionType())); methodWriter.invokeDefCall("normalizeIndex", methodType, DefBootstrap.INDEX_NORMALIZE); } @Override - protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); Type methodType = Type.getMethodType(MethodWriter.getType( @@ -57,7 +58,7 @@ protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals } @Override - protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); Type methodType = Type.getMethodType(Type.getType(void.class), Type.getType(Object.class), diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java index 3c8483b7e6099..181b35c0598a0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java @@ -22,15 +22,16 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; public class BraceSubNode extends UnaryNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - setup(classWriter, methodWriter, globals); - load(classWriter, methodWriter, globals); + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + setup(classWriter, methodWriter, globals, scopeTable); + load(classWriter, methodWriter, globals, scopeTable); } @Override @@ -39,8 +40,8 @@ protected int accessElementCount() { } @Override - protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getChildNode().write(classWriter, methodWriter, globals); + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getChildNode().write(classWriter, methodWriter, globals, scopeTable); Label noFlip = new Label(); methodWriter.dup(); @@ -53,13 +54,13 @@ protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals } @Override - protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.arrayLoad(MethodWriter.getType(getExpressionType())); } @Override - protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.arrayStore(MethodWriter.getType(getExpressionType())); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java index 405bbb77305b6..61f5d2e507cf0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java @@ -22,11 +22,12 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class BreakNode extends StatementNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.goTo(breakLabel); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java index b24adc0c1915f..91138a7c8506b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java @@ -22,12 +22,13 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class CallNode extends BinaryNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getLeftNode().write(classWriter, methodWriter, globals); - getRightNode().write(classWriter, methodWriter, globals); + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); + getRightNode().write(classWriter, methodWriter, globals, scopeTable); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java index b6fd079767653..5e9124d1eb3e3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Type; import java.util.ArrayList; @@ -72,11 +73,11 @@ public List> getTypeParameters() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); for (ExpressionNode argumentNode : getArgumentNodes()) { - argumentNode.write(classWriter, methodWriter, globals); + argumentNode.write(classWriter, methodWriter, globals, scopeTable); } // create method type from return value and arguments diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java index 6770640d9c857..961973c2ade12 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.ScopeTable; public class CallSubNode extends ArgumentsNode { @@ -50,7 +51,7 @@ public Class getBox() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); if (box.isPrimitive()) { @@ -58,7 +59,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals } for (ExpressionNode argumentNode : getArgumentNodes()) { - argumentNode.write(classWriter, methodWriter, globals); + argumentNode.write(classWriter, methodWriter, globals, scopeTable); } methodWriter.invokeMethodCall(method); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java index d00cb17557440..549fafa665943 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java @@ -23,8 +23,9 @@ import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; +import org.elasticsearch.painless.symbol.ScopeTable.Variable; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -33,7 +34,7 @@ public class CapturingFuncRefNode extends ExpressionNode { /* ---- begin node data ---- */ private String name; - private Variable captured; + private String capturedName; private FunctionRef funcRef; private String pointer; @@ -45,12 +46,12 @@ public String getName() { return name; } - public void setCaptured(Variable captured) { - this.captured = captured; + public void setCapturedName(String capturedName) { + this.capturedName = capturedName; } - public Variable getCaptured() { - return captured; + public String getCapturedName() { + return capturedName; } public void setFuncRef(FunctionRef funcRef) { @@ -72,20 +73,21 @@ public String getPointer() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); + Variable captured = scopeTable.getVariable(capturedName); if (pointer != null) { // dynamic interface: placeholder for run-time lookup methodWriter.push((String)null); - methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); + methodWriter.visitVarInsn(captured.getAsmType().getOpcode(Opcodes.ILOAD), captured.getSlot()); } else if (funcRef == null) { // typed interface, dynamic implementation - methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); - Type methodType = Type.getMethodType(MethodWriter.getType(getExpressionType()), MethodWriter.getType(captured.clazz)); + methodWriter.visitVarInsn(captured.getAsmType().getOpcode(Opcodes.ILOAD), captured.getSlot()); + Type methodType = Type.getMethodType(MethodWriter.getType(getExpressionType()), captured.getAsmType()); methodWriter.invokeDefCall(name, methodType, DefBootstrap.REFERENCE, getExpressionCanonicalTypeName()); } else { // typed interface, typed implementation - methodWriter.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot()); + methodWriter.visitVarInsn(captured.getAsmType().getOpcode(Opcodes.ILOAD), captured.getSlot()); methodWriter.invokeLambdaCall(funcRef); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java index 75b1bd2c32be5..b6475c5049dde 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessCast; +import org.elasticsearch.painless.symbol.ScopeTable; public class CastNode extends UnaryNode { @@ -41,8 +42,8 @@ public PainlessCast getCast() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getChildNode().write(classWriter, methodWriter, globals); + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getChildNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.writeDebugInfo(location); methodWriter.writeCast(cast); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java index 3bf0717757619..224a285f4d328 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java @@ -22,6 +22,8 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; +import org.elasticsearch.painless.symbol.ScopeTable.Variable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -55,23 +57,24 @@ public BlockNode getBlockNode() { Label exception = null; @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); + declarationNode.write(classWriter, methodWriter, globals, scopeTable); + Variable variable = scopeTable.getVariable(declarationNode.getName()); + Label jump = new Label(); methodWriter.mark(jump); - methodWriter.visitVarInsn(MethodWriter.getType( - declarationNode.getVariable().clazz).getOpcode(Opcodes.ISTORE), - declarationNode.getVariable().getSlot()); + methodWriter.visitVarInsn(variable.getAsmType().getOpcode(Opcodes.ISTORE), variable.getSlot()); if (blockNode != null) { blockNode.continueLabel = continueLabel; blockNode.breakLabel = breakLabel; - blockNode.write(classWriter, methodWriter, globals); + blockNode.write(classWriter, methodWriter, globals, scopeTable); } - methodWriter.visitTryCatchBlock(begin, end, jump, MethodWriter.getType(declarationNode.getVariable().clazz).getInternalName()); + methodWriter.visitTryCatchBlock(begin, end, jump, variable.getAsmType().getInternalName()); if (exception != null && (blockNode == null || blockNode.doAllEscape() == false)) { methodWriter.goTo(exception); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java index 1959902afc977..d1899ae9bc767 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java @@ -22,17 +22,18 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Constant; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals; -import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.ScriptClassInfo; import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.symbol.ScopeTable; +import org.elasticsearch.painless.symbol.ScopeTable.Variable; import org.elasticsearch.painless.symbol.ScriptRoot; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; import org.objectweb.asm.util.Printer; import java.lang.invoke.MethodType; @@ -107,10 +108,8 @@ public List getStatementsNodes() { private String sourceText; private Printer debugStream; private ScriptRoot scriptRoot; - private Locals mainMethod; private boolean doesMethodEscape; private final Set extractedVariables = new HashSet<>(); - private final List getMethods = new ArrayList<>(); public void setScriptClassInfo(ScriptClassInfo scriptClassInfo) { this.scriptClassInfo = scriptClassInfo; @@ -152,14 +151,6 @@ public ScriptRoot getScriptRoot() { return scriptRoot; } - public void setMainMethod(Locals mainMethod) { - this.mainMethod = mainMethod; - } - - public Locals getMainMethod() { - return mainMethod; - } - public void setMethodEscape(boolean doesMethodEscape) { this.doesMethodEscape = doesMethodEscape; } @@ -180,10 +171,6 @@ public Set getExtractedVariables() { return extractedVariables; } - public List getGetMethods() { - return getMethods; - } - /* ---- end node data ---- */ protected Globals globals; @@ -276,17 +263,17 @@ public Map write() { // Write the method defined in the interface: MethodWriter executeMethod = classWriter.newMethodWriter(Opcodes.ACC_PUBLIC, scriptClassInfo.getExecuteMethod()); executeMethod.visitCode(); - write(classWriter, executeMethod, globals); + write(classWriter, executeMethod, globals, new ScopeTable()); executeMethod.endMethod(); // Write all fields: for (FieldNode fieldNode : fieldNodes) { - fieldNode.write(classWriter, null, null); + fieldNode.write(classWriter, null, null, null); } // Write all functions: for (FunctionNode functionNode : functionNodes) { - functionNode.write(classWriter, null, globals); + functionNode.write(classWriter, null, globals, new ScopeTable()); } // Write the constants @@ -335,7 +322,7 @@ public Map write() { } @Override - protected void write(org.elasticsearch.painless.ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { // We wrap the whole method in a few try/catches to handle and/or convert other exceptions to ScriptException Label startTry = new Label(); Label endTry = new Label(); @@ -344,28 +331,41 @@ protected void write(org.elasticsearch.painless.ClassWriter classWriter, MethodW Label endCatch = new Label(); methodWriter.mark(startTry); + scopeTable.defineInternalVariable(Object.class, "this"); + + // Method arguments + for (ScriptClassInfo.MethodArgument arg : scriptClassInfo.getExecuteArguments()) { + scopeTable.defineVariable(arg.getClazz(), arg.getName()); + } + if (scriptRoot.getCompilerSettings().getMaxLoopCounter() > 0) { // if there is infinite loop protection, we do this once: // int #loop = settings.getMaxLoopCounter() - Variable loop = mainMethod.getVariable(null, Locals.LOOP); + Variable loop = scopeTable.defineInternalVariable(int.class, "loop"); methodWriter.push(scriptRoot.getCompilerSettings().getMaxLoopCounter()); methodWriter.visitVarInsn(Opcodes.ISTORE, loop.getSlot()); } - for (org.objectweb.asm.commons.Method method : getMethods) { + for (int getMethodIndex = 0; getMethodIndex < scriptClassInfo.getGetMethods().size(); ++getMethodIndex) { + Method method = scriptClassInfo.getGetMethods().get(getMethodIndex); + Class returnType = scriptClassInfo.getGetReturns().get(getMethodIndex); + String name = method.getName().substring(3); name = Character.toLowerCase(name.charAt(0)) + name.substring(1); - Variable variable = mainMethod.getVariable(null, name); - methodWriter.loadThis(); - methodWriter.invokeVirtual(Type.getType(scriptClassInfo.getBaseClass()), method); - methodWriter.visitVarInsn(method.getReturnType().getOpcode(Opcodes.ISTORE), variable.getSlot()); + if (extractedVariables.contains(name)) { + Variable variable = scopeTable.defineVariable(returnType, name); + + methodWriter.loadThis(); + methodWriter.invokeVirtual(Type.getType(scriptClassInfo.getBaseClass()), method); + methodWriter.visitVarInsn(method.getReturnType().getOpcode(Opcodes.ISTORE), variable.getSlot()); + } } for (StatementNode statementNode : statementNodes) { - statementNode.write(classWriter, methodWriter, globals); + statementNode.write(classWriter, methodWriter, globals, scopeTable); } if (doesMethodEscape == false) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java index 75b6136fbe294..f21a210953f7b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java @@ -26,6 +26,7 @@ import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Label; import org.objectweb.asm.Type; @@ -62,13 +63,13 @@ public String getComparisonCanonicalTypeName() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); - getLeftNode().write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); if (getRightNode() instanceof NullNode == false) { - getRightNode().write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals, scopeTable); } Label jump = new Label(); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java index f903cc297e2ff..f62ceb6848960 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -42,19 +43,19 @@ public ExpressionNode getConditionNode() { /* ---- end tree structure ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); Label fals = new Label(); Label end = new Label(); - conditionNode.write(classWriter, methodWriter, globals); + conditionNode.write(classWriter, methodWriter, globals, scopeTable); methodWriter.ifZCmp(Opcodes.IFEQ, fals); - getLeftNode().write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.goTo(end); methodWriter.mark(fals); - getRightNode().write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.mark(end); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java index 3728cc020d92f..46052bdf1eee3 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class ConstantNode extends ExpressionNode { @@ -40,7 +41,7 @@ public Object getConstant() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { if (constant instanceof String) methodWriter.push((String)constant); else if (constant instanceof Double) methodWriter.push((double)constant); else if (constant instanceof Float) methodWriter.push((float)constant); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java index 82eeeaec9015f..f62a4df7261d5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java @@ -22,11 +22,12 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class ContinueNode extends StatementNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.goTo(continueLabel); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java index 1decb6cf91f4f..c490364448fbc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import java.util.ArrayList; import java.util.List; @@ -43,9 +44,9 @@ public List getDeclarationsNodes() { /* ---- end tree structure ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { for (DeclarationNode declarationNode : declarationNodes) { - declarationNode.write(classWriter, methodWriter, globals); + declarationNode.write(classWriter, methodWriter, globals, scopeTable); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java index 2339a74c5788a..2e9ad4dfc6071 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java @@ -21,8 +21,10 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.symbol.ScopeTable; +import org.elasticsearch.painless.symbol.ScopeTable.Variable; import org.objectweb.asm.Opcodes; public class DeclarationNode extends StatementNode { @@ -41,24 +43,39 @@ public ExpressionNode getExpressionNode() { /* ---- end tree structure, begin node data ---- */ - private Variable variable; + protected String name; + protected Class declarationType; - public void setVariable(Variable variable) { - this.variable = variable; + public void setName(String name) { + this.name = name; } - public Variable getVariable() { - return variable; + public String getName() { + return name; + } + + public void setDeclarationType(Class declarationType) { + this.declarationType = declarationType; + } + + public Class getDeclarationType() { + return declarationType; + } + + public String getDeclarationCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(declarationType); } /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); + Variable variable = scopeTable.defineVariable(declarationType, name); + if (expressionNode == null) { - Class sort = variable.clazz; + Class sort = variable.getType(); if (sort == void.class || sort == boolean.class || sort == byte.class || sort == short.class || sort == char.class || sort == int.class) { @@ -73,9 +90,9 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.visitInsn(Opcodes.ACONST_NULL); } } else { - expressionNode.write(classWriter, methodWriter, globals); + expressionNode.write(classWriter, methodWriter, globals, scopeTable); } - methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); + methodWriter.visitVarInsn(variable.getAsmType().getOpcode(Opcodes.ISTORE), variable.getSlot()); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java index 2fd104666ab70..89964578e9285 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java @@ -22,15 +22,19 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; +import org.elasticsearch.painless.symbol.ScopeTable.Variable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; public class DoWhileLoopNode extends LoopNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); + scopeTable = scopeTable.newScope(); + Label start = new Label(); Label begin = new Label(); Label end = new Label(); @@ -39,17 +43,19 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals getBlockNode().continueLabel = begin; getBlockNode().breakLabel = end; - getBlockNode().write(classWriter, methodWriter, globals); + getBlockNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.mark(begin); if (isContinuous() == false) { - getConditionNode().write(classWriter, methodWriter, globals); + getConditionNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.ifZCmp(Opcodes.IFEQ, end); } - if (getLoopCounter() != null) { - methodWriter.writeLoopCounter(getLoopCounter().getSlot(), Math.max(1, getBlockNode().getStatementCount()), location); + Variable loop = scopeTable.getInternalVariable("loop"); + + if (loop != null) { + methodWriter.writeLoopCounter(loop.getSlot(), Math.max(1, getBlockNode().getStatementCount()), location); } methodWriter.goTo(start); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java index 2ea11e5f4d906..c50fa3680d5a6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java @@ -22,13 +22,14 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class DotNode extends BinaryNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getLeftNode().write(classWriter, methodWriter, globals); - getRightNode().write(classWriter, methodWriter, globals); + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); + getRightNode().write(classWriter, methodWriter, globals, scopeTable); } @Override @@ -36,19 +37,18 @@ protected int accessElementCount() { return getRightNode().accessElementCount(); } - @Override - protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getLeftNode().write(classWriter, methodWriter, globals); - getRightNode().setup(classWriter, methodWriter, globals); + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); + getRightNode().setup(classWriter, methodWriter, globals, scopeTable); } @Override - protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getRightNode().load(classWriter, methodWriter, globals); + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getRightNode().load(classWriter, methodWriter, globals, scopeTable); } @Override - protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getRightNode().store(classWriter, methodWriter, globals); + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getRightNode().store(classWriter, methodWriter, globals, scopeTable); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java index 2f32a73d74b31..4687ee14c57af 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java @@ -22,11 +22,12 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class DotSubArrayLengthNode extends ExpressionNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.arrayLength(); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java index 8be070de26e02..1e4e7820bfd2f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Type; public class DotSubDefNode extends ExpressionNode { @@ -42,7 +43,7 @@ public String getValue() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); Type methodType = Type.getMethodType(MethodWriter.getType(getExpressionType()), Type.getType(Object.class)); @@ -55,12 +56,12 @@ protected int accessElementCount() { } @Override - protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { // do nothing } @Override - protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); Type methodType = Type.getMethodType(MethodWriter.getType(getExpressionType()), Type.getType(Object.class)); @@ -68,7 +69,7 @@ protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals } @Override - protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); Type methodType = Type.getMethodType( diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java index 5dc188419c286..faab60a07ee1c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessField; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Type; public class DotSubNode extends ExpressionNode { @@ -42,7 +43,7 @@ public PainlessField getField() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { @@ -60,12 +61,12 @@ protected int accessElementCount() { } @Override - protected void setup(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { // Do nothing. } @Override - protected void load(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { @@ -78,7 +79,7 @@ protected void load(ClassWriter classWriter, MethodWriter methodWriter,Globals g } @Override - protected void store(ClassWriter classWriter, MethodWriter methodWriter,Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java index 412aef5b07d69..8552667e720e4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.ScopeTable; public class DotSubShortcutNode extends ExpressionNode { @@ -50,7 +51,7 @@ public PainlessMethod getGetter() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(getter); @@ -66,12 +67,12 @@ protected int accessElementCount() { } @Override - protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { // do nothing } @Override - protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(getter); @@ -82,7 +83,7 @@ protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals } @Override - protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(setter); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java index 43c5fbc725d73..c5ec6959410fa 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java @@ -22,21 +22,22 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Label; public class ElvisNode extends BinaryNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); Label end = new Label(); - getLeftNode().write(classWriter, methodWriter, globals); + getLeftNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.dup(); methodWriter.ifNonNull(end); methodWriter.pop(); - getRightNode().write(classWriter, methodWriter, globals); + getRightNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.mark(end); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java index b9a70eaec27aa..aa9ee2dcbb37d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Type; public class FieldNode extends IRNode { @@ -73,7 +74,7 @@ public Object getInstance() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { classWriter.getClassVisitor().visitField( ClassWriter.buildAccess(modifiers, true), name, Type.getType(fieldType).getDescriptor(), null, null).visitEnd(); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java index 76d5140a024b8..b1ff46d14c358 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class ForEachLoopNode extends StatementNode { @@ -40,7 +41,8 @@ public ConditionNode getConditionNode() { /* ---- end tree structure ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - conditionNode.write(classWriter, methodWriter, globals); + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + scopeTable = scopeTable.newScope(); + conditionNode.write(classWriter, methodWriter, globals, scopeTable); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java index 9dcb01cb1094b..3197aae1a9ac8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java @@ -21,10 +21,11 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.symbol.ScopeTable; +import org.elasticsearch.painless.symbol.ScopeTable.Variable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -32,18 +33,33 @@ public class ForEachSubArrayNode extends LoopNode { /* ---- begin node data ---- */ - private Variable variable; + private Class variableType; + private String variableName; private PainlessCast cast; - private Variable array; - private Variable index; + private Class arrayType; + private String arrayName; + private Class indexType; + private String indexName; private Class indexedType; - public void setVariable(Variable variable) { - this.variable = variable; + public void setVariableType(Class variableType) { + this.variableType = variableType; } - public Variable getVariable() { - return variable; + public Class getVariableType() { + return variableType; + } + + public String getVariableCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(variableType); + } + + public void setVariableName(String variableName) { + this.variableName = variableName; + } + + public String getVariableName() { + return variableName; } public void setCast(PainlessCast cast) { @@ -54,22 +70,46 @@ public PainlessCast getCast() { return cast; } - public void setArray(Variable array) { - this.array = array; + public void setArrayType(Class arrayType) { + this.arrayType = arrayType; + } + + public Class getArrayType() { + return arrayType; + } + + public String getArrayCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(arrayType); + } + + public void setArrayName(String arrayName) { + this.arrayName = arrayName; + } + + public String getArrayName() { + return arrayName; } - public Variable getArray() { - return array; + public void setIndexType(Class indexType) { + this.indexType = indexType; } - public void setIndex(Variable index) { - this.index = index; + public Class getIndexType() { + return indexType; } - public Variable getIndex() { - return index; + public String getIndexCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(indexType); } - + + public void setIndexName(String indexName) { + this.indexName = indexName; + } + + public String getIndexName() { + return indexName; + } + public void setIndexedType(Class indexedType) { this.indexedType = indexedType; } @@ -81,17 +121,21 @@ public Class getIndexedType() { public String getIndexedCanonicalTypeName() { return PainlessLookupUtility.typeToCanonicalTypeName(indexedType); } - + /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); - getConditionNode().write(classWriter, methodWriter, globals); - methodWriter.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ISTORE), array.getSlot()); + Variable variable = scopeTable.defineVariable(variableType, variableName); + Variable array = scopeTable.defineInternalVariable(arrayType, arrayName); + Variable index = scopeTable.defineInternalVariable(indexType, indexName); + + getConditionNode().write(classWriter, methodWriter, globals, scopeTable); + methodWriter.visitVarInsn(array.getAsmType().getOpcode(Opcodes.ISTORE), array.getSlot()); methodWriter.push(-1); - methodWriter.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ISTORE), index.getSlot()); + methodWriter.visitVarInsn(index.getAsmType().getOpcode(Opcodes.ISTORE), index.getSlot()); Label begin = new Label(); Label end = new Label(); @@ -99,24 +143,26 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.mark(begin); methodWriter.visitIincInsn(index.getSlot(), 1); - methodWriter.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ILOAD), index.getSlot()); - methodWriter.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ILOAD), array.getSlot()); + methodWriter.visitVarInsn(index.getAsmType().getOpcode(Opcodes.ILOAD), index.getSlot()); + methodWriter.visitVarInsn(array.getAsmType().getOpcode(Opcodes.ILOAD), array.getSlot()); methodWriter.arrayLength(); methodWriter.ifICmp(MethodWriter.GE, end); - methodWriter.visitVarInsn(MethodWriter.getType(array.clazz).getOpcode(Opcodes.ILOAD), array.getSlot()); - methodWriter.visitVarInsn(MethodWriter.getType(index.clazz).getOpcode(Opcodes.ILOAD), index.getSlot()); - methodWriter.arrayLoad(MethodWriter.getType(getIndexedType())); + methodWriter.visitVarInsn(array.getAsmType().getOpcode(Opcodes.ILOAD), array.getSlot()); + methodWriter.visitVarInsn(index.getAsmType().getOpcode(Opcodes.ILOAD), index.getSlot()); + methodWriter.arrayLoad(MethodWriter.getType(indexedType)); methodWriter.writeCast(cast); - methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); + methodWriter.visitVarInsn(variable.getAsmType().getOpcode(Opcodes.ISTORE), variable.getSlot()); + + Variable loop = scopeTable.getInternalVariable("loop"); - if (getLoopCounter() != null) { - methodWriter.writeLoopCounter(getLoopCounter().getSlot(), getBlockNode().getStatementCount(), location); + if (loop != null) { + methodWriter.writeLoopCounter(loop.getSlot(), getBlockNode().getStatementCount(), location); } getBlockNode().continueLabel = begin; getBlockNode().breakLabel = end; - getBlockNode().write(classWriter, methodWriter, globals); + getBlockNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.goTo(begin); methodWriter.mark(end); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java index c6c7fe63cbf18..bdb1af41c3a41 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java @@ -22,10 +22,11 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessCast; import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.ScopeTable; +import org.elasticsearch.painless.symbol.ScopeTable.Variable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -42,19 +43,29 @@ public class ForEachSubIterableNode extends LoopNode { /* ---- begin node data ---- */ - private Variable variable; + private Class variableType; + private String variableName; private PainlessCast cast; - private Variable iterator; + private Class iteratorType; + private String iteratorName; private PainlessMethod method; - public void setVariable(Variable variable) { - this.variable = variable; + public void setVariableType(Class variableType) { + this.variableType = variableType; } - public Variable getVariable() { - return variable; + public Class getVariableType() { + return variableType; } + public void setVariableName(String variableName) { + this.variableName = variableName; + } + + public String getVariableName() { + return variableName; + } + public void setCast(PainlessCast cast) { this.cast = cast; } @@ -63,12 +74,20 @@ public PainlessCast getCast() { return cast; } - public void setIterator(Variable iterator) { - this.iterator = iterator; + public void setIteratorType(Class iteratorType) { + this.iteratorType = iteratorType; + } + + public Class getIteratorType() { + return iteratorType; } - public Variable getIterator() { - return iterator; + public void setIteratorName(String iteratorName) { + this.iteratorName = iteratorName; + } + + public String getIteratorName() { + return iteratorName; } public void setMethod(PainlessMethod method) { @@ -82,10 +101,13 @@ public PainlessMethod getMethod() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); - getConditionNode().write(classWriter, methodWriter, globals); + Variable variable = scopeTable.defineVariable(variableType, variableName); + Variable iterator = scopeTable.defineInternalVariable(iteratorType, iteratorName); + + getConditionNode().write(classWriter, methodWriter, globals, scopeTable); if (method == null) { org.objectweb.asm.Type methodType = org.objectweb.asm.Type @@ -95,29 +117,31 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.invokeMethodCall(method); } - methodWriter.visitVarInsn(MethodWriter.getType(iterator.clazz).getOpcode(Opcodes.ISTORE), iterator.getSlot()); + methodWriter.visitVarInsn(iterator.getAsmType().getOpcode(Opcodes.ISTORE), iterator.getSlot()); Label begin = new Label(); Label end = new Label(); methodWriter.mark(begin); - methodWriter.visitVarInsn(MethodWriter.getType(iterator.clazz).getOpcode(Opcodes.ILOAD), iterator.getSlot()); + methodWriter.visitVarInsn(iterator.getAsmType().getOpcode(Opcodes.ILOAD), iterator.getSlot()); methodWriter.invokeInterface(ITERATOR_TYPE, ITERATOR_HASNEXT); methodWriter.ifZCmp(MethodWriter.EQ, end); - methodWriter.visitVarInsn(MethodWriter.getType(iterator.clazz).getOpcode(Opcodes.ILOAD), iterator.getSlot()); + methodWriter.visitVarInsn(iterator.getAsmType().getOpcode(Opcodes.ILOAD), iterator.getSlot()); methodWriter.invokeInterface(ITERATOR_TYPE, ITERATOR_NEXT); methodWriter.writeCast(cast); - methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); + methodWriter.visitVarInsn(variable.getAsmType().getOpcode(Opcodes.ISTORE), variable.getSlot()); + + Variable loop = scopeTable.getInternalVariable("loop"); - if (getLoopCounter() != null) { - methodWriter.writeLoopCounter(getLoopCounter().getSlot(), getBlockNode().getStatementCount(), location); + if (loop != null) { + methodWriter.writeLoopCounter(loop.getSlot(), getBlockNode().getStatementCount(), location); } getBlockNode().continueLabel = begin; getBlockNode().breakLabel = end; - getBlockNode().write(classWriter, methodWriter, globals); + getBlockNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.goTo(begin); methodWriter.mark(end); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java index df800919f88dc..a1cdabf5b6cbe 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java @@ -22,6 +22,8 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; +import org.elasticsearch.painless.symbol.ScopeTable.Variable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -48,28 +50,29 @@ public ExpressionNode getAfterthoughtNode() { return afterthoughtNode; } - /* ---- end tree structure ---- */ - @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); + scopeTable = scopeTable.newScope(); + Label start = new Label(); Label begin = afterthoughtNode == null ? start : new Label(); Label end = new Label(); if (initializerNode instanceof DeclarationBlockNode) { - initializerNode.write(classWriter, methodWriter, globals); + initializerNode.write(classWriter, methodWriter, globals, scopeTable); } else if (initializerNode instanceof ExpressionNode) { ExpressionNode initializer = (ExpressionNode)this.initializerNode; - initializer.write(classWriter, methodWriter, globals); + + initializer.write(classWriter, methodWriter, globals, scopeTable); methodWriter.writePop(MethodWriter.getType(initializer.getExpressionType()).getSize()); } methodWriter.mark(start); if (getConditionNode() != null && isContinuous() == false) { - getConditionNode().write(classWriter, methodWriter, globals); + getConditionNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.ifZCmp(Opcodes.IFEQ, end); } @@ -84,26 +87,30 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals ++statementCount; } - if (getLoopCounter() != null) { - methodWriter.writeLoopCounter(getLoopCounter().getSlot(), statementCount, location); + Variable loop = scopeTable.getInternalVariable("loop"); + + if (loop != null) { + methodWriter.writeLoopCounter(loop.getSlot(), statementCount, location); } getBlockNode().continueLabel = begin; getBlockNode().breakLabel = end; - getBlockNode().write(classWriter, methodWriter, globals); + getBlockNode().write(classWriter, methodWriter, globals, scopeTable); } else { - if (getLoopCounter() != null) { - methodWriter.writeLoopCounter(getLoopCounter().getSlot(), 1, location); + Variable loop = scopeTable.getInternalVariable("loop"); + + if (loop != null) { + methodWriter.writeLoopCounter(loop.getSlot(), 1, location); } } if (afterthoughtNode != null) { methodWriter.mark(begin); - afterthoughtNode.write(classWriter, methodWriter, globals); + afterthoughtNode.write(classWriter, methodWriter, globals, scopeTable); methodWriter.writePop(MethodWriter.getType(afterthoughtNode.getExpressionType()).getSize()); } - if (afterthoughtNode != null || !allEscape) { + if (afterthoughtNode != null || allEscape == false) { methodWriter.goTo(start); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java index 8c249a3cba703..45e56c3921b67 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class FuncRefNode extends ExpressionNode { @@ -41,7 +42,7 @@ public FunctionRef getFuncRef() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { if (funcRef != null) { methodWriter.writeDebugInfo(location); methodWriter.invokeLambdaCall(funcRef); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java index 1262f767a86be..700da1df83a0b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java @@ -21,8 +21,9 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; +import org.elasticsearch.painless.symbol.ScopeTable.Variable; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; @@ -48,10 +49,10 @@ public BlockNode getBlockNode() { private String name; private Class returnType; - private final List> typeParameters = new ArrayList<>(); + private List> typeParameters = new ArrayList<>(); + private List parameterNames = new ArrayList<>(); private boolean isSynthetic; private boolean doesMethodEscape; - private Variable loopCounter; private int maxLoopCounter; public void setName(String name) { @@ -78,6 +79,14 @@ public List> getTypeParameters() { return typeParameters; } + public void addParameterName(String parameterName) { + parameterNames.add(parameterName); + } + + public List getParameterNames() { + return parameterNames; + } + public void setSynthetic(boolean isSythetic) { this.isSynthetic = isSythetic; } @@ -94,14 +103,6 @@ public boolean doesMethodEscape() { return doesMethodEscape; } - public void setLoopCounter(Variable loopCounter) { - this.loopCounter = loopCounter; - } - - public Variable getLoopCounter() { - return loopCounter; - } - public void setMaxLoopCounter(int maxLoopCounter) { this.maxLoopCounter = maxLoopCounter; } @@ -113,7 +114,7 @@ public int getMaxLoopCounter() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC; if (isSynthetic) { @@ -124,6 +125,9 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals Type[] asmParameterTypes = new Type[typeParameters.size()]; for (int index = 0; index < asmParameterTypes.length; ++index) { + Class type = typeParameters.get(index); + String name = parameterNames.get(index); + scopeTable.defineVariable(type, name); asmParameterTypes[index] = MethodWriter.getType(typeParameters.get(index)); } @@ -135,13 +139,16 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals if (maxLoopCounter > 0) { // if there is infinite loop protection, we do this once: // int #loop = settings.getMaxLoopCounter() + + Variable loop = scopeTable.defineInternalVariable(int.class, "loop"); + methodWriter.push(maxLoopCounter); - methodWriter.visitVarInsn(Opcodes.ISTORE, loopCounter.getSlot()); + methodWriter.visitVarInsn(Opcodes.ISTORE, loop.getSlot()); } - blockNode.write(classWriter, methodWriter, globals); + blockNode.write(classWriter, methodWriter, globals, scopeTable.newScope()); - if (!doesMethodEscape) { + if (doesMethodEscape == false) { if (returnType == void.class) { methodWriter.returnValue(); } else { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java index 7a955e17aff13..e8624c5a1699a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public abstract class IRNode { @@ -40,10 +41,23 @@ public Location getLocation() { /* end node data */ - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + throw new UnsupportedOperationException(); + } + + protected int accessElementCount() { + throw new UnsupportedOperationException(); + } + + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + throw new UnsupportedOperationException(); + } + + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + throw new UnsupportedOperationException(); + } - protected int accessElementCount() {throw new UnsupportedOperationException();} - protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} - protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} - protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) {throw new UnsupportedOperationException();} + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + throw new UnsupportedOperationException(); + } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java index 267dd5d737328..ede3c583884d9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -42,18 +43,18 @@ public BlockNode getElseBlockNode() { /* ---- end tree structure ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); Label fals = new Label(); Label end = new Label(); - getConditionNode().write(classWriter, methodWriter, globals); + getConditionNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.ifZCmp(Opcodes.IFEQ, fals); getBlockNode().continueLabel = continueLabel; getBlockNode().breakLabel = breakLabel; - getBlockNode().write(classWriter, methodWriter, globals); + getBlockNode().write(classWriter, methodWriter, globals, scopeTable.newScope()); if (getBlockNode().doAllEscape() == false) { methodWriter.goTo(end); @@ -63,7 +64,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals elseBlockNode.continueLabel = continueLabel; elseBlockNode.breakLabel = breakLabel; - elseBlockNode.write(classWriter, methodWriter, globals); + elseBlockNode.write(classWriter, methodWriter, globals, scopeTable.newScope()); methodWriter.mark(end); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java index d151a87f66c34..05639fe177627 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java @@ -22,23 +22,24 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; public class IfNode extends ConditionNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); Label fals = new Label(); - getConditionNode().write(classWriter, methodWriter, globals); + getConditionNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.ifZCmp(Opcodes.IFEQ, fals); getBlockNode().continueLabel = continueLabel; getBlockNode().breakLabel = breakLabel; - getBlockNode().write(classWriter, methodWriter, globals); + getBlockNode().write(classWriter, methodWriter, globals, scopeTable.newScope()); methodWriter.mark(fals); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java index 7dc8c3c8c50fd..c825d3c941ecf 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Type; public class InstanceofNode extends UnaryNode { @@ -68,8 +69,8 @@ public boolean isPrimitiveResult() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getChildNode().write(classWriter, methodWriter, globals); + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getChildNode().write(classWriter, methodWriter, globals, scopeTable); // primitive types if (isPrimitiveResult) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java index 267df6c54e1f0..1a5a3e016d855 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java @@ -22,8 +22,9 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; +import org.elasticsearch.painless.symbol.ScopeTable.Variable; import org.objectweb.asm.Opcodes; import java.util.ArrayList; @@ -33,14 +34,14 @@ public class LambdaNode extends ExpressionNode { /* ---- begin node data ---- */ - private final List captures = new ArrayList<>(); + private final List captures = new ArrayList<>(); private FunctionRef funcRef; - public void addCapture(Variable capture) { + public void addCapture(String capture) { captures.add(capture); } - public List getCaptures() { + public List getCaptures() { return captures; } @@ -55,14 +56,15 @@ public FunctionRef getFuncRef() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); if (funcRef != null) { methodWriter.writeDebugInfo(location); // load captures - for (Variable capture : captures) { - methodWriter.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); + for (String capture : captures) { + Variable variable = scopeTable.getVariable(capture); + methodWriter.visitVarInsn(variable.getAsmType().getOpcode(Opcodes.ILOAD), variable.getSlot()); } methodWriter.invokeLambdaCall(funcRef); @@ -70,8 +72,9 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals // placeholder methodWriter.push((String)null); // load captures - for (Variable capture : captures) { - methodWriter.visitVarInsn(MethodWriter.getType(capture.clazz).getOpcode(Opcodes.ILOAD), capture.getSlot()); + for (String capture : captures) { + Variable variable = scopeTable.getVariable(capture); + methodWriter.visitVarInsn(variable.getAsmType().getOpcode(Opcodes.ILOAD), variable.getSlot()); } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java index a0cefdc4bfed4..304beade56265 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java @@ -24,6 +24,7 @@ import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; @@ -53,7 +54,7 @@ public PainlessMethod getMethod() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.newInstance(MethodWriter.getType(getExpressionType())); @@ -63,7 +64,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals for (ExpressionNode argument : getArgumentNodes()) { methodWriter.dup(); - argument.write(classWriter, methodWriter, globals); + argument.write(classWriter, methodWriter, globals, scopeTable); methodWriter.invokeMethodCall(method); methodWriter.pop(); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java index f902fca25a9be..7b3602c9cc5e8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java @@ -24,6 +24,7 @@ import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.WriterConstants; import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -53,9 +54,9 @@ public PainlessMethod getGetter() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - setup(classWriter, methodWriter, globals); - load(classWriter, methodWriter, globals); + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + setup(classWriter, methodWriter, globals, scopeTable); + load(classWriter, methodWriter, globals, scopeTable); } @Override @@ -64,8 +65,8 @@ protected int accessElementCount() { } @Override - protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getChildNode().write(classWriter, methodWriter, globals); + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getChildNode().write(classWriter, methodWriter, globals, scopeTable); Label noFlip = new Label(); methodWriter.dup(); @@ -78,7 +79,7 @@ protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals } @Override - protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(getter); @@ -88,7 +89,7 @@ protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals } @Override - protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(setter); methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java index dc3a546d7de05..7822917009bd9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LoopNode.java @@ -19,14 +19,11 @@ package org.elasticsearch.painless.ir; -import org.elasticsearch.painless.Locals.Variable; - public abstract class LoopNode extends ConditionNode { /* ---- begin node data ---- */ private boolean isContinuous; - private Variable loopCounter; public void setContinuous(boolean isContinuous) { this.isContinuous = isContinuous; @@ -36,14 +33,6 @@ public boolean isContinuous() { return isContinuous; } - public void setLoopCounter(Variable loopCounter) { - this.loopCounter = loopCounter; - } - - public Variable getLoopCounter() { - return loopCounter; - } - /* ---- end node data ---- */ } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java index f3411f837c5d8..788f157a95419 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java @@ -24,6 +24,7 @@ import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessConstructor; import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; @@ -86,7 +87,7 @@ public PainlessMethod getMethod() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.newInstance(MethodWriter.getType(getExpressionType())); @@ -96,8 +97,8 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals for (int index = 0; index < getArgumentsSize(); ++index) { methodWriter.dup(); - getKeyNode(index).write(classWriter, methodWriter, globals); - getValueNode(index).write(classWriter, methodWriter, globals); + getKeyNode(index).write(classWriter, methodWriter, globals, scopeTable); + getValueNode(index).write(classWriter, methodWriter, globals, scopeTable); methodWriter.invokeMethodCall(method); methodWriter.pop(); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java index f151ca89b2fa0..f1e012099a57a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessMethod; +import org.elasticsearch.painless.symbol.ScopeTable; public class MapSubShortcutNode extends UnaryNode { @@ -50,8 +51,8 @@ public PainlessMethod getGetter() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getChildNode().write(classWriter, methodWriter, globals); + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getChildNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(getter); @@ -67,12 +68,12 @@ protected int accessElementCount() { } @Override - protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - getChildNode().write(classWriter, methodWriter, globals); + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + getChildNode().write(classWriter, methodWriter, globals, scopeTable); } @Override - protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(getter); @@ -82,7 +83,7 @@ protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals } @Override - protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.invokeMethodCall(setter); methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize()); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java index 74cbe5c32ad41..7055b82fd03ff 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class NewArrayFuncRefNode extends ExpressionNode { @@ -41,7 +42,7 @@ public FunctionRef getFuncRef() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { if (funcRef != null) { methodWriter.writeDebugInfo(location); methodWriter.invokeLambdaCall(funcRef); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java index d2f26efe4c0ca..c63b811b5990c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class NewArrayNode extends ArgumentsNode { @@ -40,7 +41,7 @@ public boolean getInitialize() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); if (initialize) { @@ -52,12 +53,12 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals methodWriter.dup(); methodWriter.push(index); - argumentNode.write(classWriter, methodWriter, globals); + argumentNode.write(classWriter, methodWriter, globals, scopeTable); methodWriter.arrayStore(MethodWriter.getType(getExpressionType().getComponentType())); } } else { for (ExpressionNode argumentNode : getArgumentNodes()) { - argumentNode.write(classWriter, methodWriter, globals); + argumentNode.write(classWriter, methodWriter, globals, scopeTable); } if (getArgumentNodes().size() > 1) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java index f92bb753e0a63..cb40eb7cb33e5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java @@ -23,6 +23,7 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.lookup.PainlessConstructor; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; @@ -52,7 +53,7 @@ public boolean getRead() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.newInstance(MethodWriter.getType(getExpressionType())); @@ -62,7 +63,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals } for (ExpressionNode argumentNode : getArgumentNodes()) { - argumentNode.write(classWriter, methodWriter, globals); + argumentNode.write(classWriter, methodWriter, globals, scopeTable); } methodWriter.invokeConstructor( diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java index 91baae23ab28a..60e9d43fa1cab 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java @@ -22,12 +22,13 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Opcodes; public class NullNode extends ExpressionNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.visitInsn(Opcodes.ACONST_NULL); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java index 61585b13e926d..c89c0700d8060 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java @@ -22,18 +22,19 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Label; public class NullSafeSubNode extends UnaryNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); Label end = new Label(); methodWriter.dup(); methodWriter.ifNull(end); - getChildNode().write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.mark(end); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java index dc4f042332b83..988f2c4bcc9af 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java @@ -24,6 +24,7 @@ import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.WriterConstants; +import org.elasticsearch.painless.symbol.ScopeTable; import java.util.regex.Pattern; @@ -62,7 +63,7 @@ public Object getConstant() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); methodWriter.getStatic(WriterConstants.CLASS_TYPE, constant.name, org.objectweb.asm.Type.getType(Pattern.class)); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java index 8752b6fd915c9..5a0d2687bcd13 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class ReturnNode extends StatementNode { @@ -40,11 +41,11 @@ public ExpressionNode getExpressionNode() { /* ---- end tree structure ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); if (expressionNode != null) { - expressionNode.write(classWriter, methodWriter, globals); + expressionNode.write(classWriter, methodWriter, globals, scopeTable); } methodWriter.returnValue(); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java index 95c2195f62ae4..6d045bdb7f8c0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class StatementExpressionNode extends StatementNode { @@ -52,9 +53,9 @@ public boolean getMethodEscape() { /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); - expressionNode.write(classWriter, methodWriter, globals); + expressionNode.write(classWriter, methodWriter, globals, scopeTable); if (methodEscape) { methodWriter.returnValue(); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java index f144f4e601d7b..2b0409982f88f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java @@ -22,11 +22,12 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class StaticNode extends ExpressionNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { // do nothing } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java index dec6cec871b43..77f5dffea8bcf 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; public class ThrowNode extends StatementNode { @@ -40,9 +41,9 @@ public ExpressionNode getExpressionNode() { /* ---- end tree structure ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); - expressionNode.write(classWriter, methodWriter, globals); + expressionNode.write(classWriter, methodWriter, globals, scopeTable); methodWriter.throwException(); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java index 7a89a6fadb600..c621e1348ec4a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java @@ -22,6 +22,7 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Label; import java.util.ArrayList; @@ -53,7 +54,7 @@ public List getCatchsNodes() { /* ---- end tree structure ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); Label begin = new Label(); @@ -64,7 +65,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals blockNode.continueLabel = continueLabel; blockNode.breakLabel = breakLabel; - blockNode.write(classWriter, methodWriter, globals); + blockNode.write(classWriter, methodWriter, globals, scopeTable.newScope()); if (blockNode.doAllEscape() == false) { methodWriter.goTo(exception); @@ -76,7 +77,7 @@ protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals catchNode.begin = begin; catchNode.end = end; catchNode.exception = catchNodes.size() > 1 ? exception : null; - catchNode.write(classWriter, methodWriter, globals); + catchNode.write(classWriter, methodWriter, globals, scopeTable.newScope()); } if (blockNode.doAllEscape() == false || catchNodes.size() > 1) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java index ea6d08579039c..66369d8e202f0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java @@ -26,6 +26,7 @@ import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.def; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -78,14 +79,14 @@ public boolean getOriginallyExplicit() { /* ---- end node data ---- */ @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); if (operation == Operation.NOT) { Label fals = new Label(); Label end = new Label(); - getChildNode().write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.ifZCmp(Opcodes.IFEQ, fals); methodWriter.push(false); @@ -94,7 +95,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl methodWriter.push(true); methodWriter.mark(end); } else { - getChildNode().write(classWriter, methodWriter, globals); + getChildNode().write(classWriter, methodWriter, globals, scopeTable); // Def calls adopt the wanted return value. If there was a narrowing cast, // we need to flag that so that it's done at runtime. diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java index 9c2323b27cb73..3044b71c9bd59 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnboundCallNode.java @@ -26,6 +26,7 @@ import org.elasticsearch.painless.lookup.PainlessInstanceBinding; import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.symbol.FunctionTable.LocalFunction; +import org.elasticsearch.painless.symbol.ScopeTable; import org.objectweb.asm.Label; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; @@ -94,18 +95,18 @@ public String getBindingName() { /* ---- end node data ---- */ @Override - public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeDebugInfo(location); if (localFunction != null) { for (ExpressionNode argumentNode : getArgumentNodes()) { - argumentNode.write(classWriter, methodWriter, globals); + argumentNode.write(classWriter, methodWriter, globals, scopeTable); } methodWriter.invokeStatic(CLASS_TYPE, localFunction.getAsmMethod()); } else if (importedMethod != null) { for (ExpressionNode argumentNode : getArgumentNodes()) { - argumentNode.write(classWriter, methodWriter, globals); + argumentNode.write(classWriter, methodWriter, globals, scopeTable); } methodWriter.invokeStatic(Type.getType(importedMethod.targetClass), @@ -128,7 +129,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl } for (int argument = 0; argument < javaConstructorParameterCount; ++argument) { - getArgumentNodes().get(argument).write(classWriter, methodWriter, globals); + getArgumentNodes().get(argument).write(classWriter, methodWriter, globals, scopeTable); } methodWriter.invokeConstructor(type, Method.getMethod(classBinding.javaConstructor)); @@ -139,7 +140,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl methodWriter.getField(CLASS_TYPE, bindingName, type); for (int argument = 0; argument < classBinding.javaMethod.getParameterCount(); ++argument) { - getArgumentNodes().get(argument + javaConstructorParameterCount).write(classWriter, methodWriter, globals); + getArgumentNodes().get(argument + javaConstructorParameterCount).write(classWriter, methodWriter, globals, scopeTable); } methodWriter.invokeVirtual(type, Method.getMethod(classBinding.javaMethod)); @@ -150,7 +151,7 @@ public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals gl methodWriter.getStatic(CLASS_TYPE, bindingName, type); for (int argument = 0; argument < instanceBinding.javaMethod.getParameterCount(); ++argument) { - getArgumentNodes().get(argument).write(classWriter, methodWriter, globals); + getArgumentNodes().get(argument).write(classWriter, methodWriter, globals, scopeTable); } methodWriter.invokeVirtual(type, Method.getMethod(instanceBinding.javaMethod)); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java index 37af99a09c3a9..68f2f08e2e52f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java @@ -21,29 +21,31 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; -import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; +import org.elasticsearch.painless.symbol.ScopeTable.Variable; import org.objectweb.asm.Opcodes; public class VariableNode extends ExpressionNode { /* ---- begin node data ---- */ - private Variable variable; + private String name; - public void setVariable(Variable variable) { - this.variable = variable; + public void setName(String name) { + this.name = name; } - public Variable getVariable() { - return variable; + public String getName() { + return name; } /* ---- end node data ---- */ @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ILOAD), variable.getSlot()); + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + Variable variable = scopeTable.getVariable(name); + methodWriter.visitVarInsn(variable.getAsmType().getOpcode(Opcodes.ILOAD), variable.getSlot()); } @Override @@ -52,17 +54,19 @@ protected int accessElementCount() { } @Override - protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { // do nothing } @Override - protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ILOAD), variable.getSlot()); + protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + Variable variable = scopeTable.getVariable(name); + methodWriter.visitVarInsn(variable.getAsmType().getOpcode(Opcodes.ILOAD), variable.getSlot()); } @Override - protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { - methodWriter.visitVarInsn(MethodWriter.getType(variable.clazz).getOpcode(Opcodes.ISTORE), variable.getSlot()); + protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { + Variable variable = scopeTable.getVariable(name); + methodWriter.visitVarInsn(variable.getAsmType().getOpcode(Opcodes.ISTORE), variable.getSlot()); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java index 6f918e66f37fb..3e5df7d8a2e04 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java @@ -22,36 +22,44 @@ import org.elasticsearch.painless.ClassWriter; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.symbol.ScopeTable; +import org.elasticsearch.painless.symbol.ScopeTable.Variable; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; public class WhileNode extends LoopNode { @Override - protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals) { + protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) { methodWriter.writeStatementOffset(location); + scopeTable = scopeTable.newScope(); + Label begin = new Label(); Label end = new Label(); methodWriter.mark(begin); if (isContinuous() == false) { - getConditionNode().write(classWriter, methodWriter, globals); + getConditionNode().write(classWriter, methodWriter, globals, scopeTable); methodWriter.ifZCmp(Opcodes.IFEQ, end); } if (getBlockNode() != null) { - if (getLoopCounter() != null) { - methodWriter.writeLoopCounter(getLoopCounter().getSlot(), Math.max(1, getBlockNode().getStatementCount()), location); + Variable loop = scopeTable.getInternalVariable("loop"); + + if (loop != null) { + methodWriter.writeLoopCounter(loop.getSlot(), Math.max(1, getBlockNode().getStatementCount()), location); } getBlockNode().continueLabel = begin; getBlockNode().breakLabel = end; - getBlockNode().write(classWriter, methodWriter, globals); + getBlockNode().write(classWriter, methodWriter, globals, scopeTable); } else { - if (getLoopCounter() != null) { - methodWriter.writeLoopCounter(getLoopCounter().getSlot(), 1, location); + Variable loop = scopeTable.getInternalVariable("loop"); + + if (loop != null) { + methodWriter.writeLoopCounter(loop.getSlot(), 1, location); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java index ed098df80fd31..58eee1c923d54 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java @@ -85,13 +85,12 @@ CapturingFuncRefNode write() { capturingFuncRefNode.setLocation(location); capturingFuncRefNode.setExpressionType(actual); - capturingFuncRefNode.setCaptured(captured); + capturingFuncRefNode.setCapturedName(captured.name); capturingFuncRefNode.setName(call); capturingFuncRefNode.setPointer(defPointer); capturingFuncRefNode.setFuncRef(ref);; return capturingFuncRefNode; - } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java index 01341dee87a1c..dad16eaee3de8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java @@ -191,7 +191,10 @@ LambdaNode write() { lambdaNode.setLocation(location); lambdaNode.setExpressionType(actual); lambdaNode.setFuncRef(ref); - lambdaNode.getCaptures().addAll(captures); + + for (Variable capture : captures) { + lambdaNode.addCapture(capture.name); + } return lambdaNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EVariable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EVariable.java index 62661210a6242..f0018bbc5d46f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EVariable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EVariable.java @@ -65,7 +65,7 @@ VariableNode write() { variableNode.setLocation(location); variableNode.setExpressionType(actual); - variableNode.setVariable(variable); + variableNode.setName(name); return variableNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java index f343f0d1b443d..f69e7a52839fb 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SClass.java @@ -192,16 +192,12 @@ public ClassNode writeClass() { classNode.setDebugStream(debugStream); classNode.setName(name); classNode.setSourceText(sourceText); - classNode.setMainMethod(mainMethod); classNode.setMethodEscape(methodEscape); - classNode.getGetMethods().addAll(getMethods); classNode.getExtractedVariables().addAll(extractedVariables); return classNode; } - - @Override public String toString() { List subs = new ArrayList<>(functions.size() + statements.size()); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java index 877c1dbd04911..d82bb09d91204 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java @@ -33,7 +33,7 @@ */ public final class SDeclaration extends AStatement { - private final DType type; + private DType type; private final String name; private AExpression expression; @@ -59,6 +59,7 @@ void extractVariables(Set variables) { @Override void analyze(ScriptRoot scriptRoot, Locals locals) { DResolvedType resolvedType = type.resolveType(scriptRoot.getPainlessLookup()); + type = resolvedType; if (expression != null) { expression.expected = resolvedType.getType(); @@ -76,7 +77,8 @@ DeclarationNode write() { declarationNode.setExpressionNode(expression == null ? null : expression.write()); declarationNode.setLocation(location); - declarationNode.setVariable(variable); + declarationNode.setDeclarationType(((DResolvedType)type).getType()); + declarationNode.setName(name); return declarationNode; } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java index 41a9da5afbe75..1e6e9ea4ba71a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java @@ -101,7 +101,6 @@ DoWhileLoopNode write() { doWhileLoopNode.setBlockNode(block.write()); doWhileLoopNode.setLocation(location); - doWhileLoopNode.setLoopCounter(loopCounter); doWhileLoopNode.setContinuous(continuous); return doWhileLoopNode; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java index 8ed1f0b1481b7..4c159c4c2e671 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java @@ -160,7 +160,6 @@ ForLoopNode write() { forLoopNode.setBlockNode(block == null ? null : block.write()); forLoopNode.setLocation(location); - forLoopNode.setLoopCounter(loopCounter); forLoopNode.setContinuous(continuous); return forLoopNode; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java index c1f135a344a8b..2cd2e57ee687c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java @@ -150,9 +150,9 @@ FunctionNode writeFunction() { functionNode.setName(name); functionNode.setReturnType(returnType); functionNode.getTypeParameters().addAll(typeParameters); + functionNode.getParameterNames().addAll(paramNameStrs); functionNode.setSynthetic(synthetic); functionNode.setMethodEscape(methodEscape); - functionNode.setLoopCounter(loopCounter); functionNode.setMaxLoopCounter(maxLoopCounter); return functionNode; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java index 33a33d8a1b702..bb280f5c02e13 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java @@ -75,12 +75,14 @@ ForEachSubArrayNode write() { forEachSubArrayNode.setBlockNode(block.write()); forEachSubArrayNode.setLocation(location); - forEachSubArrayNode.setVariable(variable); + forEachSubArrayNode.setVariableType(variable.clazz); + forEachSubArrayNode.setVariableName(variable.name); forEachSubArrayNode.setCast(cast); - forEachSubArrayNode.setArray(array); - forEachSubArrayNode.setIndex(index); + forEachSubArrayNode.setArrayType(array.clazz); + forEachSubArrayNode.setArrayName(array.name.substring(1)); + forEachSubArrayNode.setIndexType(index.clazz); + forEachSubArrayNode.setIndexName(index.name.substring(1)); forEachSubArrayNode.setIndexedType(indexed); - forEachSubArrayNode.setLoopCounter(loopCounter); forEachSubArrayNode.setContinuous(false); return forEachSubArrayNode; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java index 5ed45207361f9..afa96e8058e93 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java @@ -90,11 +90,12 @@ ForEachSubIterableNode write() { forEachSubIterableNode.setBlockNode(block.write()); forEachSubIterableNode.setLocation(location); - forEachSubIterableNode.setVariable(variable); + forEachSubIterableNode.setVariableType(variable.clazz); + forEachSubIterableNode.setVariableName(variable.name); forEachSubIterableNode.setCast(cast); - forEachSubIterableNode.setIterator(iterator); + forEachSubIterableNode.setIteratorType(iterator.clazz); + forEachSubIterableNode.setIteratorName(iterator.name.substring(1)); forEachSubIterableNode.setMethod(method); - forEachSubIterableNode.setLoopCounter(loopCounter); forEachSubIterableNode.setContinuous(false); return forEachSubIterableNode; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java index 18e4894bb29bd..a05046191274f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java @@ -105,7 +105,6 @@ WhileNode write() { whileNode.setBlockNode(block == null ? null : block.write()); whileNode.setLocation(location); - whileNode.setLoopCounter(loopCounter); whileNode.setContinuous(continuous); return whileNode; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScopeTable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScopeTable.java new file mode 100644 index 0000000000000..78648ad893b53 --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/symbol/ScopeTable.java @@ -0,0 +1,118 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless.symbol; + +import org.elasticsearch.painless.MethodWriter; +import org.elasticsearch.painless.lookup.PainlessLookupUtility; +import org.objectweb.asm.Type; + +import java.util.HashMap; +import java.util.Map; + +public class ScopeTable { + + public static class Variable { + protected final Class type; + protected final Type asmType; + protected final String name; + protected final int slot; + + public Variable(Class type, String name, int slot) { + this.type = type; + this.asmType = MethodWriter.getType(type); + this.name = name; + this.slot = slot; + } + + public Class getType() { + return type; + } + + public String getCanonicalTypeName() { + return PainlessLookupUtility.typeToCanonicalTypeName(type); + } + + public Type getAsmType() { + return asmType; + } + + public String getName() { + return name; + } + + public int getSlot() { + return slot; + } + } + + protected final ScopeTable parent; + protected final Map variables = new HashMap<>(); + protected int nextSlot; + + public ScopeTable() { + this.parent = null; + this.nextSlot = 0; + } + + protected ScopeTable(ScopeTable parent, int nextSlot) { + this.parent = parent; + this.nextSlot = nextSlot; + } + + public ScopeTable newScope() { + return new ScopeTable(this, nextSlot); + } + + public Variable defineVariable(Class type, String name) { + Variable variable = new Variable(type, name, nextSlot); + nextSlot += variable.getAsmType().getSize(); + variables.put(name, variable); + + return variable; + } + + /** + * Prepends the character '#' to the variable name. The '#' is + * reserved and ensures that these internal variables aren't + * accessed by a normal consumer. + */ + public Variable defineInternalVariable(Class type, String name) { + return defineVariable(type, "#" + name); + } + + public Variable getVariable(String name) { + Variable variable = variables.get(name); + + if (variable == null && parent != null) { + variable = parent.getVariable(name); + } + + return variable; + } + + /** + * Prepends the character '#' to the variable name. The '#' is + * reserved and ensures that these internal variables aren't + * accessed by a normal consumer. + */ + public Variable getInternalVariable(String name) { + return getVariable("#" + name); + } +}