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<Class<?>> 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<StatementNode> getStatementsNodes() { private String sourceText; private Printer debugStream; private ScriptRoot scriptRoot; - private Locals mainMethod; private boolean doesMethodEscape; private final Set<String> extractedVariables = new HashSet<>(); - private final List<org.objectweb.asm.commons.Method> 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<String> getExtractedVariables() { return extractedVariables; } - public List<org.objectweb.asm.commons.Method> getGetMethods() { - return getMethods; - } - /* ---- end node data ---- */ protected Globals globals; @@ -276,17 +263,17 @@ public Map<String, Object> 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<String, Object> 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<DeclarationNode> 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<Class<?>> typeParameters = new ArrayList<>(); + private List<Class<?>> typeParameters = new ArrayList<>(); + private List<String> 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<Class<?>> getTypeParameters() { return typeParameters; } + public void addParameterName(String parameterName) { + parameterNames.add(parameterName); + } + + public List<String> 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<Variable> captures = new ArrayList<>(); + private final List<String> captures = new ArrayList<>(); private FunctionRef funcRef; - public void addCapture(Variable capture) { + public void addCapture(String capture) { captures.add(capture); } - public List<Variable> getCaptures() { + public List<String> 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<CatchNode> 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<Object> 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<String> 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<String, Variable> 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); + } +}