Browse Source

Simplify constant handling in Painless (#52612)

This change makes constant handling simpler by doing the following:
* Removes the ir tree node RegexNode entirely in favor or using more 
generic nodes such as ConstantNode and MemberFieldLoadNode 
generated by the user tree node ERegex. This requires a clinit method 
added to the ClassNode, but allows for additional removals. This clinit 
method can also be used for potential optimization passes.
* Removes the Constant class as with the changes to regex nodes it's no 
longer necessary.
* Removes the Globals class from the ir tree write phase. With the previous 
removals, Globals is no longer necessary.
Jack Conradson 5 years ago
parent
commit
37e339101e
67 changed files with 518 additions and 517 deletions
  1. 0 19
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ClassWriter.java
  2. 36 36
      modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrapInjectionPhase.java
  3. 39 37
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptInjectionPhase.java
  4. 12 11
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/AssignmentNode.java
  5. 7 8
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BinaryMathNode.java
  6. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BlockNode.java
  7. 5 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BooleanNode.java
  8. 10 11
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceNode.java
  9. 7 8
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubDefNode.java
  10. 7 8
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BraceSubNode.java
  11. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java
  12. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java
  13. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java
  14. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java
  15. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java
  16. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java
  17. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java
  18. 27 28
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ClassNode.java
  19. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java
  20. 4 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java
  21. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java
  22. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java
  23. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java
  24. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java
  25. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java
  26. 10 11
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java
  27. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java
  28. 4 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java
  29. 4 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java
  30. 4 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java
  31. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java
  32. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java
  33. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java
  34. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java
  35. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java
  36. 6 7
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java
  37. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java
  38. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java
  39. 4 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java
  40. 4 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java
  41. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java
  42. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/InstanceofNode.java
  43. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java
  44. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java
  45. 7 8
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java
  46. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java
  47. 6 7
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java
  48. 9 10
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MemberCallNode.java
  49. 6 7
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MemberFieldLoadNode.java
  50. 88 0
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MemberFieldStoreNode.java
  51. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java
  52. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java
  53. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java
  54. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java
  55. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java
  56. 0 93
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java
  57. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java
  58. 4 22
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java
  59. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java
  60. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java
  61. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java
  62. 4 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java
  63. 4 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java
  64. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java
  65. 88 22
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java
  66. 18 7
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java
  67. 19 0
      modules/lang-painless/src/test/java/org/elasticsearch/painless/FactoryTests.java

+ 0 - 19
modules/lang-painless/src/main/java/org/elasticsearch/painless/ClassWriter.java

@@ -65,7 +65,6 @@ public class ClassWriter implements Closeable  {
 
     protected final org.objectweb.asm.ClassWriter classWriter;
     protected final ClassVisitor classVisitor;
-    protected MethodWriter clinitWriter = null;
 
     public ClassWriter(CompilerSettings compilerSettings, BitSet statements, Printer debugStream,
             Class<?> baseClass, int classFrames, int classAccess, String className, String[] classInterfaces) {
@@ -93,30 +92,12 @@ public class ClassWriter implements Closeable  {
         return classVisitor;
     }
 
-    /**
-     * Lazy loads the {@link MethodWriter} for clinit, so that if it's not
-     * necessary the method is never created for the class.
-     */
-    public MethodWriter getClinitWriter() {
-        if (clinitWriter == null) {
-            clinitWriter = new MethodWriter(Opcodes.ACC_STATIC, WriterConstants.CLINIT, classVisitor, statements, compilerSettings);
-            clinitWriter.visitCode();
-        }
-
-        return clinitWriter;
-    }
-
     public MethodWriter newMethodWriter(int access, Method method) {
         return new MethodWriter(access, method, classVisitor, statements, compilerSettings);
     }
 
     @Override
     public void close() {
-        if (clinitWriter != null) {
-            clinitWriter.returnValue();
-            clinitWriter.endMethod();
-        }
-
         classVisitor.visitEnd();
     }
 

+ 36 - 36
modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrapInjectionPhase.java

@@ -23,7 +23,7 @@ import org.elasticsearch.painless.ir.CallSubNode;
 import org.elasticsearch.painless.ir.ClassNode;
 import org.elasticsearch.painless.ir.FieldNode;
 import org.elasticsearch.painless.ir.FunctionNode;
-import org.elasticsearch.painless.ir.MemberFieldNode;
+import org.elasticsearch.painless.ir.MemberFieldLoadNode;
 import org.elasticsearch.painless.ir.ReturnNode;
 import org.elasticsearch.painless.ir.StaticNode;
 import org.elasticsearch.painless.ir.VariableNode;
@@ -121,50 +121,50 @@ public class DefBootstrapInjectionPhase {
             callSubNode.setLocation(internalLocation);
             callSubNode.setExpressionType(CallSite.class);
             callSubNode.setMethod(new PainlessMethod(
-                            DefBootstrap.class.getMethod("bootstrap",
-                                    PainlessLookup.class,
-                                    FunctionTable.class,
-                                    Lookup.class,
-                                    String.class,
-                                    MethodType.class,
-                                    int.class,
-                                    int.class,
-                                    Object[].class),
-                            DefBootstrap.class,
-                            CallSite.class,
-                            Arrays.asList(
-                                    PainlessLookup.class,
-                                    FunctionTable.class,
-                                    Lookup.class,
-                                    String.class,
-                                    MethodType.class,
-                                    int.class,
-                                    int.class,
-                                    Object[].class),
-                            null,
-                            null,
-                            null
+                    DefBootstrap.class.getMethod("bootstrap",
+                            PainlessLookup.class,
+                            FunctionTable.class,
+                            Lookup.class,
+                            String.class,
+                            MethodType.class,
+                            int.class,
+                            int.class,
+                            Object[].class),
+                    DefBootstrap.class,
+                    CallSite.class,
+                    Arrays.asList(
+                            PainlessLookup.class,
+                            FunctionTable.class,
+                            Lookup.class,
+                            String.class,
+                            MethodType.class,
+                            int.class,
+                            int.class,
+                            Object[].class),
+                    null,
+                    null,
+                    null
                     )
             );
             callSubNode.setBox(DefBootstrap.class);
 
             callNode.setRightNode(callSubNode);
 
-            MemberFieldNode memberFieldNode = new MemberFieldNode();
-            memberFieldNode.setLocation(internalLocation);
-            memberFieldNode.setExpressionType(PainlessLookup.class);
-            memberFieldNode.setName("$DEFINITION");
-            memberFieldNode.setStatic(true);
+            MemberFieldLoadNode memberFieldLoadNode = new MemberFieldLoadNode();
+            memberFieldLoadNode.setLocation(internalLocation);
+            memberFieldLoadNode.setExpressionType(PainlessLookup.class);
+            memberFieldLoadNode.setName("$DEFINITION");
+            memberFieldLoadNode.setStatic(true);
 
-            callSubNode.addArgumentNode(memberFieldNode);
+            callSubNode.addArgumentNode(memberFieldLoadNode);
 
-            memberFieldNode = new MemberFieldNode();
-            memberFieldNode.setLocation(internalLocation);
-            memberFieldNode.setExpressionType(FunctionTable.class);
-            memberFieldNode.setName("$FUNCTIONS");
-            memberFieldNode.setStatic(true);
+            memberFieldLoadNode = new MemberFieldLoadNode();
+            memberFieldLoadNode.setLocation(internalLocation);
+            memberFieldLoadNode.setExpressionType(FunctionTable.class);
+            memberFieldLoadNode.setName("$FUNCTIONS");
+            memberFieldLoadNode.setStatic(true);
 
-            callSubNode.addArgumentNode(memberFieldNode);
+            callSubNode.addArgumentNode(memberFieldLoadNode);
 
             VariableNode variableNode = new VariableNode();
             variableNode.setLocation(internalLocation);

+ 39 - 37
modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptInjectionPhase.java

@@ -29,7 +29,7 @@ import org.elasticsearch.painless.ir.DeclarationNode;
 import org.elasticsearch.painless.ir.FieldNode;
 import org.elasticsearch.painless.ir.FunctionNode;
 import org.elasticsearch.painless.ir.MemberCallNode;
-import org.elasticsearch.painless.ir.MemberFieldNode;
+import org.elasticsearch.painless.ir.MemberFieldLoadNode;
 import org.elasticsearch.painless.ir.ReturnNode;
 import org.elasticsearch.painless.ir.StatementNode;
 import org.elasticsearch.painless.ir.StaticNode;
@@ -131,13 +131,13 @@ public class ScriptInjectionPhase {
 
         blockNode.addStatementNode(returnNode);
 
-        MemberFieldNode memberFieldNode = new MemberFieldNode();
-        memberFieldNode.setLocation(internalLocation);
-        memberFieldNode.setExpressionType(String.class);
-        memberFieldNode.setName("$NAME");
-        memberFieldNode.setStatic(true);
+        MemberFieldLoadNode memberFieldLoadNode = new MemberFieldLoadNode();
+        memberFieldLoadNode.setLocation(internalLocation);
+        memberFieldLoadNode.setExpressionType(String.class);
+        memberFieldLoadNode.setName("$NAME");
+        memberFieldLoadNode.setStatic(true);
 
-        returnNode.setExpressionNode(memberFieldNode);
+        returnNode.setExpressionNode(memberFieldLoadNode);
 
         functionNode = new FunctionNode();
         functionNode.setLocation(internalLocation);
@@ -162,13 +162,13 @@ public class ScriptInjectionPhase {
 
         blockNode.addStatementNode(returnNode);
 
-        memberFieldNode = new MemberFieldNode();
-        memberFieldNode.setLocation(internalLocation);
-        memberFieldNode.setExpressionType(String.class);
-        memberFieldNode.setName("$SOURCE");
-        memberFieldNode.setStatic(true);
+        memberFieldLoadNode = new MemberFieldLoadNode();
+        memberFieldLoadNode.setLocation(internalLocation);
+        memberFieldLoadNode.setExpressionType(String.class);
+        memberFieldLoadNode.setName("$SOURCE");
+        memberFieldLoadNode.setStatic(true);
 
-        returnNode.setExpressionNode(memberFieldNode);
+        returnNode.setExpressionNode(memberFieldLoadNode);
 
         functionNode = new FunctionNode();
         functionNode.setLocation(internalLocation);
@@ -193,13 +193,13 @@ public class ScriptInjectionPhase {
 
         blockNode.addStatementNode(returnNode);
 
-        memberFieldNode = new MemberFieldNode();
-        memberFieldNode.setLocation(internalLocation);
-        memberFieldNode.setExpressionType(BitSet.class);
-        memberFieldNode.setName("$STATEMENTS");
-        memberFieldNode.setStatic(true);
+        memberFieldLoadNode = new MemberFieldLoadNode();
+        memberFieldLoadNode.setLocation(internalLocation);
+        memberFieldLoadNode.setExpressionType(BitSet.class);
+        memberFieldLoadNode.setName("$STATEMENTS");
+        memberFieldLoadNode.setStatic(true);
 
-        returnNode.setExpressionNode(memberFieldNode);
+        returnNode.setExpressionNode(memberFieldLoadNode);
     }
 
     // convert gets methods to a new set of inserted ir nodes as necessary -
@@ -338,11 +338,11 @@ public class ScriptInjectionPhase {
             memberCallNode.setLocation(internalLocation);
             memberCallNode.setExpressionType(ScriptException.class);
             memberCallNode.setLocalFunction(new LocalFunction(
-                            "convertToScriptException",
-                            ScriptException.class,
-                            Arrays.asList(Throwable.class, Map.class),
-                            true,
-                            false
+                    "convertToScriptException",
+                    ScriptException.class,
+                    Arrays.asList(Throwable.class, Map.class),
+                    true,
+                    false
                     )
             );
 
@@ -382,17 +382,18 @@ public class ScriptInjectionPhase {
                     null,
                     null,
                     null
-            ));
+                    )
+            );
 
             callNode.setRightNode(callSubNode);
 
-            MemberFieldNode memberFieldNode = new MemberFieldNode();
-            memberFieldNode.setLocation(internalLocation);
-            memberFieldNode.setExpressionType(PainlessLookup.class);
-            memberFieldNode.setName("$DEFINITION");
-            memberFieldNode.setStatic(true);
+            MemberFieldLoadNode memberFieldLoadNode = new MemberFieldLoadNode();
+            memberFieldLoadNode.setLocation(internalLocation);
+            memberFieldLoadNode.setExpressionType(PainlessLookup.class);
+            memberFieldLoadNode.setName("$DEFINITION");
+            memberFieldLoadNode.setStatic(true);
 
-            callSubNode.addArgumentNode(memberFieldNode);
+            callSubNode.addArgumentNode(memberFieldLoadNode);
 
             for (Class<?> throwable : new Class<?>[] {
                     PainlessError.class, BootstrapMethodError.class, OutOfMemoryError.class, StackOverflowError.class, Exception.class}) {
@@ -429,11 +430,11 @@ public class ScriptInjectionPhase {
                 memberCallNode.setLocation(internalLocation);
                 memberCallNode.setExpressionType(ScriptException.class);
                 memberCallNode.setLocalFunction(new LocalFunction(
-                                "convertToScriptException",
-                                ScriptException.class,
-                                Arrays.asList(Throwable.class, Map.class),
-                                true,
-                                false
+                        "convertToScriptException",
+                        ScriptException.class,
+                        Arrays.asList(Throwable.class, Map.class),
+                        true,
+                        false
                         )
                 );
 
@@ -470,7 +471,8 @@ public class ScriptInjectionPhase {
                         null,
                         null,
                         null
-                ));
+                        )
+                );
 
                 callNode.setRightNode(callSubNode);
             }

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

@@ -22,7 +22,6 @@ package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
 import org.elasticsearch.painless.DefBootstrap;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.Operation;
 import org.elasticsearch.painless.lookup.PainlessCast;
@@ -114,7 +113,7 @@ public class AssignmentNode extends BinaryNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         // For the case where the assignment represents a String concatenation
@@ -129,7 +128,7 @@ public class AssignmentNode extends BinaryNode {
         }
 
         // call the setup method on the lhs to prepare for a load/store operation
-        getLeftNode().setup(classWriter, methodWriter, globals, scopeTable);
+        getLeftNode().setup(classWriter, methodWriter, scopeTable);
 
         if (cat) {
             // Handle the case where we are doing a compound assignment
@@ -137,10 +136,10 @@ public class AssignmentNode extends BinaryNode {
 
             methodWriter.writeDup(getLeftNode().accessElementCount(), catElementStackSize); // dup the top element and insert it
                                                                                             // before concat helper on stack
-            getLeftNode().load(classWriter, methodWriter, globals, scopeTable);             // read the current lhs's value
+            getLeftNode().load(classWriter, methodWriter, scopeTable);             // read the current lhs's value
             methodWriter.writeAppendStrings(getLeftNode().getExpressionType()); // append the lhs's value using the StringBuilder
 
-            getRightNode().write(classWriter, methodWriter, globals, scopeTable); // write the bytecode for the rhs
+            getRightNode().write(classWriter, methodWriter, 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) {
@@ -158,14 +157,15 @@ public class AssignmentNode extends BinaryNode {
             }
 
             // store the lhs's value from the stack in its respective variable/field/array
-            getLeftNode().store(classWriter, methodWriter, globals, scopeTable);
+            getLeftNode().store(classWriter, methodWriter, 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, scopeTable); // load the current lhs's value
+
+            getLeftNode().load(classWriter, methodWriter, 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
@@ -175,7 +175,8 @@ public class AssignmentNode extends BinaryNode {
 
             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, scopeTable); // write the bytecode for the rhs
+
+            getRightNode().write(classWriter, methodWriter, 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.
@@ -196,11 +197,11 @@ public class AssignmentNode extends BinaryNode {
             }
 
             // store the lhs's value from the stack in its respective variable/field/array
-            getLeftNode().store(classWriter, methodWriter, globals, scopeTable);
+            getLeftNode().store(classWriter, methodWriter, scopeTable);
         } else {
             // Handle the case for a simple write.
 
-            getRightNode().write(classWriter, methodWriter, globals, scopeTable); // write the bytecode for the rhs rhs
+            getRightNode().write(classWriter, methodWriter, scopeTable); // write the bytecode for the rhs rhs
 
             if (read) {
                 // dup the value if the lhs is also read from
@@ -209,7 +210,7 @@ public class AssignmentNode extends BinaryNode {
             }
 
             // store the lhs's value from the stack in its respective variable/field/array
-            getLeftNode().store(classWriter, methodWriter, globals, scopeTable);
+            getLeftNode().store(classWriter, methodWriter, scopeTable);
         }
     }
 }

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

@@ -21,7 +21,6 @@ package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
 import org.elasticsearch.painless.DefBootstrap;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.Operation;
@@ -99,7 +98,7 @@ public class BinaryMathNode extends BinaryNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         if (getBinaryType() == String.class && operation == Operation.ADD) {
@@ -107,13 +106,13 @@ public class BinaryMathNode extends BinaryNode {
                 methodWriter.writeNewStrings();
             }
 
-            getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
+            getLeftNode().write(classWriter, methodWriter, scopeTable);
 
             if (getLeftNode() instanceof BinaryMathNode == false || ((BinaryMathNode)getLeftNode()).getCat() == false) {
                 methodWriter.writeAppendStrings(getLeftNode().getExpressionType());
             }
 
-            getRightNode().write(classWriter, methodWriter, globals, scopeTable);
+            getRightNode().write(classWriter, methodWriter, scopeTable);
 
             if (getRightNode() instanceof BinaryMathNode == false || ((BinaryMathNode)getRightNode()).getCat() == false) {
                 methodWriter.writeAppendStrings(getRightNode().getExpressionType());
@@ -123,8 +122,8 @@ public class BinaryMathNode extends BinaryNode {
                 methodWriter.writeToStrings();
             }
         } else if (operation == Operation.FIND || operation == Operation.MATCH) {
-            getRightNode().write(classWriter, methodWriter, globals, scopeTable);
-            getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
+            getRightNode().write(classWriter, methodWriter, scopeTable);
+            getLeftNode().write(classWriter, methodWriter, scopeTable);
             methodWriter.invokeVirtual(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_MATCHER);
 
             if (operation == Operation.FIND) {
@@ -136,8 +135,8 @@ public class BinaryMathNode extends BinaryNode {
                         "for type [" + getExpressionCanonicalTypeName() + "]");
             }
         } else {
-            getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
-            getRightNode().write(classWriter, methodWriter, globals, scopeTable);
+            getLeftNode().write(classWriter, methodWriter, scopeTable);
+            getRightNode().write(classWriter, methodWriter, scopeTable);
 
             if (binaryType == def.class || (shiftType != null && shiftType == def.class)) {
                 // def calls adopt the wanted return value. if there was a narrowing cast,

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

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 
@@ -65,11 +64,11 @@ public class BlockNode extends StatementNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         for (StatementNode statementNode : statementNodes) {
             statementNode.continueLabel = continueLabel;
             statementNode.breakLabel = breakLabel;
-            statementNode.write(classWriter, methodWriter, globals, scopeTable);
+            statementNode.write(classWriter, methodWriter, scopeTable);
         }
     }
 }

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

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.Operation;
 import org.elasticsearch.painless.symbol.ScopeTable;
@@ -44,16 +43,16 @@ public class BooleanNode extends BinaryNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         if (operation == Operation.AND) {
             Label fals = new Label();
             Label end = new Label();
 
-            getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
+            getLeftNode().write(classWriter, methodWriter, scopeTable);
             methodWriter.ifZCmp(Opcodes.IFEQ, fals);
-            getRightNode().write(classWriter, methodWriter, globals, scopeTable);
+            getRightNode().write(classWriter, methodWriter, scopeTable);
             methodWriter.ifZCmp(Opcodes.IFEQ, fals);
 
             methodWriter.push(true);
@@ -66,9 +65,9 @@ public class BooleanNode extends BinaryNode {
             Label fals = new Label();
             Label end = new Label();
 
-            getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
+            getLeftNode().write(classWriter, methodWriter, scopeTable);
             methodWriter.ifZCmp(Opcodes.IFNE, tru);
-            getRightNode().write(classWriter, methodWriter, globals, scopeTable);
+            getRightNode().write(classWriter, methodWriter, scopeTable);
             methodWriter.ifZCmp(Opcodes.IFEQ, fals);
 
             methodWriter.mark(tru);

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

@@ -20,16 +20,15 @@
 package org.elasticsearch.painless.ir;
 
 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, ScopeTable scopeTable) {
-        getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
-        getRightNode().write(classWriter, methodWriter, globals, scopeTable);
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getLeftNode().write(classWriter, methodWriter, scopeTable);
+        getRightNode().write(classWriter, methodWriter, scopeTable);
     }
 
     @Override
@@ -38,18 +37,18 @@ public class BraceNode extends BinaryNode {
     }
 
     @Override
-    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
-        getRightNode().setup(classWriter, methodWriter, globals, scopeTable);
+    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getLeftNode().write(classWriter, methodWriter, scopeTable);
+        getRightNode().setup(classWriter, methodWriter, scopeTable);
     }
 
     @Override
-    protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        getRightNode().load(classWriter, methodWriter, globals, scopeTable);
+    protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getRightNode().load(classWriter, methodWriter, scopeTable);
     }
 
     @Override
-    protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        getRightNode().store(classWriter, methodWriter, globals, scopeTable);
+    protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getRightNode().store(classWriter, methodWriter, scopeTable);
     }
 }

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

@@ -21,7 +21,6 @@ package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
 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;
@@ -29,9 +28,9 @@ import org.objectweb.asm.Type;
 public class BraceSubDefNode extends UnaryNode {
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        setup(classWriter, methodWriter, globals, scopeTable);
-        load(classWriter, methodWriter, globals, scopeTable);
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        setup(classWriter, methodWriter, scopeTable);
+        load(classWriter, methodWriter, scopeTable);
     }
 
     @Override
@@ -40,16 +39,16 @@ public class BraceSubDefNode extends UnaryNode {
     }
 
     @Override
-    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.dup();
-        getChildNode().write(classWriter, methodWriter, globals, scopeTable);
+        getChildNode().write(classWriter, methodWriter, 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, ScopeTable scopeTable) {
+    protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         Type methodType = Type.getMethodType(MethodWriter.getType(
@@ -58,7 +57,7 @@ public class BraceSubDefNode extends UnaryNode {
     }
 
     @Override
-    protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         Type methodType = Type.getMethodType(Type.getType(void.class), Type.getType(Object.class),

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

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -29,9 +28,9 @@ import org.objectweb.asm.Opcodes;
 public class BraceSubNode extends UnaryNode {
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        setup(classWriter, methodWriter, globals, scopeTable);
-        load(classWriter, methodWriter, globals, scopeTable);
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        setup(classWriter, methodWriter, scopeTable);
+        load(classWriter, methodWriter, scopeTable);
     }
 
     @Override
@@ -40,8 +39,8 @@ public class BraceSubNode extends UnaryNode {
     }
 
     @Override
-    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        getChildNode().write(classWriter, methodWriter, globals, scopeTable);
+    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getChildNode().write(classWriter, methodWriter, scopeTable);
 
         Label noFlip = new Label();
         methodWriter.dup();
@@ -54,13 +53,13 @@ public class BraceSubNode extends UnaryNode {
     }
 
     @Override
-    protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
         methodWriter.arrayLoad(MethodWriter.getType(getExpressionType()));
     }
 
     @Override
-    protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
         methodWriter.arrayStore(MethodWriter.getType(getExpressionType()));
     }

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/BreakNode.java

@@ -20,14 +20,13 @@
 package org.elasticsearch.painless.ir;
 
 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, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.goTo(breakLabel);
     }
 }

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallNode.java

@@ -20,15 +20,14 @@
 package org.elasticsearch.painless.ir;
 
 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, ScopeTable scopeTable) {
-        getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
-        getRightNode().write(classWriter, methodWriter, globals, scopeTable);
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getLeftNode().write(classWriter, methodWriter, scopeTable);
+        getRightNode().write(classWriter, methodWriter, scopeTable);
     }
 }

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubDefNode.java

@@ -21,7 +21,6 @@ package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
 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;
@@ -73,11 +72,11 @@ public class CallSubDefNode extends ArgumentsNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         for (ExpressionNode argumentNode : getArgumentNodes()) {
-            argumentNode.write(classWriter, methodWriter, globals, scopeTable);
+            argumentNode.write(classWriter, methodWriter, scopeTable);
         }
 
         // create method type from return value and arguments

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CallSubNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessMethod;
 import org.elasticsearch.painless.symbol.ScopeTable;
@@ -51,7 +50,7 @@ public class CallSubNode extends ArgumentsNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         if (box.isPrimitive()) {
@@ -59,7 +58,7 @@ public class CallSubNode extends ArgumentsNode {
         }
 
         for (ExpressionNode argumentNode : getArgumentNodes()) {
-            argumentNode.write(classWriter, methodWriter, globals, scopeTable);
+            argumentNode.write(classWriter, methodWriter, scopeTable);
         }
 
         methodWriter.invokeMethodCall(method);

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CapturingFuncRefNode.java

@@ -22,7 +22,6 @@ package org.elasticsearch.painless.ir;
 import org.elasticsearch.painless.ClassWriter;
 import org.elasticsearch.painless.DefBootstrap;
 import org.elasticsearch.painless.FunctionRef;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 import org.elasticsearch.painless.symbol.ScopeTable.Variable;
@@ -73,7 +72,7 @@ public class CapturingFuncRefNode extends ExpressionNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
         Variable captured = scopeTable.getVariable(capturedName);
         if (pointer != null) {

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CastNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessCast;
 import org.elasticsearch.painless.symbol.ScopeTable;
@@ -42,8 +41,8 @@ public class CastNode extends UnaryNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        getChildNode().write(classWriter, methodWriter, globals, scopeTable);
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getChildNode().write(classWriter, methodWriter, scopeTable);
         methodWriter.writeDebugInfo(location);
         methodWriter.writeCast(cast);
     }

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/CatchNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -57,10 +56,10 @@ public class CatchNode extends StatementNode {
     Label exception = null;
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
 
-        declarationNode.write(classWriter, methodWriter, globals, scopeTable);
+        declarationNode.write(classWriter, methodWriter, scopeTable);
         Variable variable = scopeTable.getVariable(declarationNode.getName());
 
         Label jump = new Label();
@@ -71,7 +70,7 @@ public class CatchNode extends StatementNode {
         if (blockNode != null) {
             blockNode.continueLabel = continueLabel;
             blockNode.breakLabel = breakLabel;
-            blockNode.write(classWriter, methodWriter, globals, scopeTable);
+            blockNode.write(classWriter, methodWriter, scopeTable);
         }
 
         methodWriter.visitTryCatchBlock(begin, end, jump, variable.getAsmType().getInternalName());

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

@@ -20,23 +20,20 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Constant;
-import org.elasticsearch.painless.Globals;
 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.ScriptRoot;
 import org.objectweb.asm.ClassVisitor;
 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;
 import java.util.ArrayList;
 import java.util.BitSet;
-import java.util.Collection;
 import java.util.List;
 
 import static org.elasticsearch.painless.WriterConstants.BASE_INTERFACE_TYPE;
@@ -48,6 +45,7 @@ public class ClassNode extends IRNode {
 
     private final List<FieldNode> fieldNodes = new ArrayList<>();
     private final List<FunctionNode> functionNodes = new ArrayList<>();
+    private final BlockNode clinitBlockNode;
 
     public void addFieldNode(FieldNode fieldNode) {
         fieldNodes.add(fieldNode);
@@ -64,7 +62,11 @@ public class ClassNode extends IRNode {
     public List<FunctionNode> getFunctionsNodes() {
         return functionNodes;
     }
-    
+
+    public BlockNode getClinitBlockNode() {
+        return clinitBlockNode;
+    }
+
     /* ---- end tree structure, begin node data ---- */
 
     private ScriptClassInfo scriptClassInfo;
@@ -115,11 +117,16 @@ public class ClassNode extends IRNode {
 
     /* ---- end node data ---- */
 
-    protected Globals globals;
+    public ClassNode() {
+        clinitBlockNode = new BlockNode();
+        clinitBlockNode.setLocation(new Location("internal$clinit$blocknode", 0));
+        clinitBlockNode.setAllEscape(true);
+        clinitBlockNode.setStatementCount(1);
+    }
 
     public byte[] write() {
-        globals = new Globals(new BitSet(sourceText.length()));
-        scriptRoot.addStaticConstant("$STATEMENTS", globals.getStatements());
+        BitSet statements = new BitSet(sourceText.length());
+        scriptRoot.addStaticConstant("$STATEMENTS", statements);
 
         // Create the ClassWriter.
 
@@ -129,7 +136,7 @@ public class ClassNode extends IRNode {
         String className = CLASS_TYPE.getInternalName();
         String[] classInterfaces = new String[] { interfaceBase };
 
-        ClassWriter classWriter = new ClassWriter(scriptRoot.getCompilerSettings(), globals.getStatements(), debugStream,
+        ClassWriter classWriter = new ClassWriter(scriptRoot.getCompilerSettings(), statements, debugStream,
                 scriptClassInfo.getBaseClass(), classFrames, classAccess, className, classInterfaces);
         ClassVisitor classVisitor = classWriter.getClassVisitor();
         classVisitor.visitSource(Location.computeSourceName(name), null);
@@ -152,34 +159,26 @@ public class ClassNode extends IRNode {
         constructor.returnValue();
         constructor.endMethod();
 
+        if (clinitBlockNode.getStatementsNodes().isEmpty() == false) {
+            MethodWriter methodWriter = classWriter.newMethodWriter(
+                    Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
+                    new Method("<clinit>", Type.getType(void.class), new Type[0]));
+            clinitBlockNode.write(classWriter, methodWriter, new ScopeTable());
+            methodWriter.returnValue();
+            methodWriter.endMethod();
+        }
+
         // Write all fields:
         for (FieldNode fieldNode : fieldNodes) {
-            fieldNode.write(classWriter, null, null, null);
+            fieldNode.write(classWriter, null, null);
         }
 
         // Write all functions:
         for (FunctionNode functionNode : functionNodes) {
-            functionNode.write(classWriter, null, globals, new ScopeTable());
-        }
-
-        // Write the constants
-        if (false == globals.getConstantInitializers().isEmpty()) {
-            Collection<Constant> inits = globals.getConstantInitializers().values();
-
-            // Initialize the constants in a static initializer
-            final MethodWriter clinit = new MethodWriter(Opcodes.ACC_STATIC,
-                    WriterConstants.CLINIT, classVisitor, globals.getStatements(), scriptRoot.getCompilerSettings());
-            clinit.visitCode();
-            for (Constant constant : inits) {
-                constant.initializer.accept(clinit);
-                clinit.putStatic(CLASS_TYPE, constant.name, constant.type);
-            }
-            clinit.returnValue();
-            clinit.endMethod();
+            functionNode.write(classWriter, null, new ScopeTable());
         }
 
         // End writing the class and store the generated bytes.
-
         classVisitor.visitEnd();
         return classWriter.getClassBytes();
     }

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ComparisonNode.java

@@ -21,7 +21,6 @@ package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
 import org.elasticsearch.painless.DefBootstrap;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.Operation;
 import org.elasticsearch.painless.lookup.PainlessLookupUtility;
@@ -63,13 +62,13 @@ public class ComparisonNode extends BinaryNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
-        getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
+        getLeftNode().write(classWriter, methodWriter, scopeTable);
 
         if (getRightNode() instanceof NullNode == false) {
-            getRightNode().write(classWriter, methodWriter, globals, scopeTable);
+            getRightNode().write(classWriter, methodWriter, scopeTable);
         }
 
         Label jump = new Label();

+ 4 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConditionalNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -43,19 +42,19 @@ public class ConditionalNode extends BinaryNode {
     /* ---- end tree structure ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         Label fals = new Label();
         Label end = new Label();
 
-        conditionNode.write(classWriter, methodWriter, globals, scopeTable);
+        conditionNode.write(classWriter, methodWriter, scopeTable);
         methodWriter.ifZCmp(Opcodes.IFEQ, fals);
 
-        getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
+        getLeftNode().write(classWriter, methodWriter, scopeTable);
         methodWriter.goTo(end);
         methodWriter.mark(fals);
-        getRightNode().write(classWriter, methodWriter, globals, scopeTable);
+        getRightNode().write(classWriter, methodWriter, scopeTable);
         methodWriter.mark(end);
     }
 }

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ConstantNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 
@@ -41,7 +40,7 @@ public class ConstantNode extends ExpressionNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, 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);

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ContinueNode.java

@@ -20,14 +20,13 @@
 package org.elasticsearch.painless.ir;
 
 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, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.goTo(continueLabel);
     }
 }

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationBlockNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 
@@ -44,9 +43,9 @@ public final class DeclarationBlockNode extends StatementNode {
     /* ---- end tree structure ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         for (DeclarationNode declarationNode : declarationNodes) {
-            declarationNode.write(classWriter, methodWriter, globals, scopeTable);
+            declarationNode.write(classWriter, methodWriter, scopeTable);
         }
     }
 }

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DeclarationNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessLookupUtility;
 import org.elasticsearch.painless.symbol.ScopeTable;
@@ -78,7 +77,7 @@ public class DeclarationNode extends StatementNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
 
         Variable variable = scopeTable.defineVariable(declarationType, name);
@@ -101,7 +100,7 @@ public class DeclarationNode extends StatementNode {
                 }
             }
         } else {
-            expressionNode.write(classWriter, methodWriter, globals, scopeTable);
+            expressionNode.write(classWriter, methodWriter, scopeTable);
         }
 
         methodWriter.visitVarInsn(variable.getAsmType().getOpcode(Opcodes.ISTORE), variable.getSlot());

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DoWhileLoopNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -30,7 +29,7 @@ import org.objectweb.asm.Opcodes;
 public class DoWhileLoopNode extends LoopNode {
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
 
         scopeTable = scopeTable.newScope();
@@ -43,12 +42,12 @@ public class DoWhileLoopNode extends LoopNode {
 
         getBlockNode().continueLabel = begin;
         getBlockNode().breakLabel = end;
-        getBlockNode().write(classWriter, methodWriter, globals, scopeTable);
+        getBlockNode().write(classWriter, methodWriter, scopeTable);
 
         methodWriter.mark(begin);
 
         if (isContinuous() == false) {
-            getConditionNode().write(classWriter, methodWriter, globals, scopeTable);
+            getConditionNode().write(classWriter, methodWriter, scopeTable);
             methodWriter.ifZCmp(Opcodes.IFEQ, end);
         }
 

+ 10 - 11
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotNode.java

@@ -20,16 +20,15 @@
 package org.elasticsearch.painless.ir;
 
 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, ScopeTable scopeTable) {
-        getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
-        getRightNode().write(classWriter, methodWriter, globals, scopeTable);
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getLeftNode().write(classWriter, methodWriter, scopeTable);
+        getRightNode().write(classWriter, methodWriter, scopeTable);
     }
 
     @Override
@@ -37,18 +36,18 @@ public class DotNode extends BinaryNode {
         return getRightNode().accessElementCount();
     }
 
-    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
-        getRightNode().setup(classWriter, methodWriter, globals, scopeTable);
+    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getLeftNode().write(classWriter, methodWriter, scopeTable);
+        getRightNode().setup(classWriter, methodWriter, scopeTable);
     }
 
     @Override
-    protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        getRightNode().load(classWriter, methodWriter, globals, scopeTable);
+    protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getRightNode().load(classWriter, methodWriter, scopeTable);
     }
 
     @Override
-    protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        getRightNode().store(classWriter, methodWriter, globals, scopeTable);
+    protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getRightNode().store(classWriter, methodWriter, scopeTable);
     }
 }

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubArrayLengthNode.java

@@ -20,14 +20,13 @@
 package org.elasticsearch.painless.ir;
 
 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, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
         methodWriter.arrayLength();
     }

+ 4 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubDefNode.java

@@ -21,7 +21,6 @@ package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
 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;
@@ -43,7 +42,7 @@ public class DotSubDefNode extends ExpressionNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         Type methodType = Type.getMethodType(MethodWriter.getType(getExpressionType()), Type.getType(Object.class));
@@ -56,12 +55,12 @@ public class DotSubDefNode extends ExpressionNode {
     }
 
     @Override
-    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         // do nothing
     }
 
     @Override
-    protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         Type methodType = Type.getMethodType(MethodWriter.getType(getExpressionType()), Type.getType(Object.class));
@@ -69,7 +68,7 @@ public class DotSubDefNode extends ExpressionNode {
     }
 
     @Override
-    protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         Type methodType = Type.getMethodType(

+ 4 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessField;
 import org.elasticsearch.painless.symbol.ScopeTable;
@@ -43,7 +42,7 @@ public class DotSubNode extends ExpressionNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) {
@@ -61,12 +60,12 @@ public class DotSubNode extends ExpressionNode {
     }
 
     @Override
-    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         // Do nothing.
     }
 
     @Override
-    protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) {
@@ -79,7 +78,7 @@ public class DotSubNode extends ExpressionNode {
     }
 
     @Override
-    protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         if (java.lang.reflect.Modifier.isStatic(field.javaField.getModifiers())) {

+ 4 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/DotSubShortcutNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessMethod;
 import org.elasticsearch.painless.symbol.ScopeTable;
@@ -51,7 +50,7 @@ public class DotSubShortcutNode extends ExpressionNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         methodWriter.invokeMethodCall(getter);
@@ -67,12 +66,12 @@ public class DotSubShortcutNode extends ExpressionNode {
     }
 
     @Override
-    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         // do nothing
     }
 
     @Override
-    protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         methodWriter.invokeMethodCall(getter);
@@ -83,7 +82,7 @@ public class DotSubShortcutNode extends ExpressionNode {
     }
 
     @Override
-    protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         methodWriter.invokeMethodCall(setter);

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ElvisNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -28,16 +27,16 @@ import org.objectweb.asm.Label;
 public class ElvisNode extends BinaryNode {
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         Label end = new Label();
 
-        getLeftNode().write(classWriter, methodWriter, globals, scopeTable);
+        getLeftNode().write(classWriter, methodWriter, scopeTable);
         methodWriter.dup();
         methodWriter.ifNonNull(end);
         methodWriter.pop();
-        getRightNode().write(classWriter, methodWriter, globals, scopeTable);
+        getRightNode().write(classWriter, methodWriter, scopeTable);
         methodWriter.mark(end);
     }
 }

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FieldNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessLookupUtility;
 import org.elasticsearch.painless.symbol.ScopeTable;
@@ -65,7 +64,7 @@ public class FieldNode extends IRNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         classWriter.getClassVisitor().visitField(
                 ClassWriter.buildAccess(modifiers, true), name, Type.getType(fieldType).getDescriptor(), null, null).visitEnd();
     }

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachLoopNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 
@@ -41,8 +40,8 @@ public class ForEachLoopNode extends StatementNode {
     /* ---- end tree structure ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         scopeTable = scopeTable.newScope();
-        conditionNode.write(classWriter, methodWriter, globals, scopeTable);
+        conditionNode.write(classWriter, methodWriter, scopeTable);
     }
 }

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubArrayNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessCast;
 import org.elasticsearch.painless.lookup.PainlessLookupUtility;
@@ -125,14 +124,14 @@ public class ForEachSubArrayNode extends LoopNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
 
         Variable variable = scopeTable.defineVariable(variableType, variableName);
         Variable array = scopeTable.defineInternalVariable(arrayType, arrayName);
         Variable index = scopeTable.defineInternalVariable(indexType, indexName);
 
-        getConditionNode().write(classWriter, methodWriter, globals, scopeTable);
+        getConditionNode().write(classWriter, methodWriter, scopeTable);
         methodWriter.visitVarInsn(array.getAsmType().getOpcode(Opcodes.ISTORE), array.getSlot());
         methodWriter.push(-1);
         methodWriter.visitVarInsn(index.getAsmType().getOpcode(Opcodes.ISTORE), index.getSlot());
@@ -162,7 +161,7 @@ public class ForEachSubArrayNode extends LoopNode {
 
         getBlockNode().continueLabel = begin;
         getBlockNode().breakLabel = end;
-        getBlockNode().write(classWriter, methodWriter, globals, scopeTable);
+        getBlockNode().write(classWriter, methodWriter, scopeTable);
 
         methodWriter.goTo(begin);
         methodWriter.mark(end);

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForEachSubIterableNode.java

@@ -21,7 +21,6 @@ package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
 import org.elasticsearch.painless.DefBootstrap;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessCast;
 import org.elasticsearch.painless.lookup.PainlessMethod;
@@ -101,13 +100,13 @@ public class ForEachSubIterableNode extends LoopNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
 
         Variable variable = scopeTable.defineVariable(variableType, variableName);
         Variable iterator = scopeTable.defineInternalVariable(iteratorType, iteratorName);
 
-        getConditionNode().write(classWriter, methodWriter, globals, scopeTable);
+        getConditionNode().write(classWriter, methodWriter, scopeTable);
 
         if (method == null) {
             org.objectweb.asm.Type methodType = org.objectweb.asm.Type
@@ -141,7 +140,7 @@ public class ForEachSubIterableNode extends LoopNode {
 
         getBlockNode().continueLabel = begin;
         getBlockNode().breakLabel = end;
-        getBlockNode().write(classWriter, methodWriter, globals, scopeTable);
+        getBlockNode().write(classWriter, methodWriter, scopeTable);
 
         methodWriter.goTo(begin);
         methodWriter.mark(end);

+ 6 - 7
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ForLoopNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -51,7 +50,7 @@ public class ForLoopNode extends LoopNode {
     }
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
 
         scopeTable = scopeTable.newScope();
@@ -61,18 +60,18 @@ public class ForLoopNode extends LoopNode {
         Label end = new Label();
 
         if (initializerNode instanceof DeclarationBlockNode) {
-            initializerNode.write(classWriter, methodWriter, globals, scopeTable);
+            initializerNode.write(classWriter, methodWriter, scopeTable);
         } else if (initializerNode instanceof ExpressionNode) {
             ExpressionNode initializer = (ExpressionNode)this.initializerNode;
 
-            initializer.write(classWriter, methodWriter, globals, scopeTable);
+            initializer.write(classWriter, methodWriter, scopeTable);
             methodWriter.writePop(MethodWriter.getType(initializer.getExpressionType()).getSize());
         }
 
         methodWriter.mark(start);
 
         if (getConditionNode() != null && isContinuous() == false) {
-            getConditionNode().write(classWriter, methodWriter, globals, scopeTable);
+            getConditionNode().write(classWriter, methodWriter, scopeTable);
             methodWriter.ifZCmp(Opcodes.IFEQ, end);
         }
 
@@ -95,7 +94,7 @@ public class ForLoopNode extends LoopNode {
 
             getBlockNode().continueLabel = begin;
             getBlockNode().breakLabel = end;
-            getBlockNode().write(classWriter, methodWriter, globals, scopeTable);
+            getBlockNode().write(classWriter, methodWriter, scopeTable);
         } else {
             Variable loop = scopeTable.getInternalVariable("loop");
 
@@ -106,7 +105,7 @@ public class ForLoopNode extends LoopNode {
 
         if (afterthoughtNode != null) {
             methodWriter.mark(begin);
-            afterthoughtNode.write(classWriter, methodWriter, globals, scopeTable);
+            afterthoughtNode.write(classWriter, methodWriter, scopeTable);
             methodWriter.writePop(MethodWriter.getType(afterthoughtNode.getExpressionType()).getSize());
         }
 

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FuncRefNode.java

@@ -21,7 +21,6 @@ package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
 import org.elasticsearch.painless.FunctionRef;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 
@@ -42,7 +41,7 @@ public class FuncRefNode extends ExpressionNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         if (funcRef != null) {
             methodWriter.writeDebugInfo(location);
             methodWriter.invokeLambdaCall(funcRef);

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/FunctionNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -123,7 +122,7 @@ public class FunctionNode extends IRNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         int access = Opcodes.ACC_PUBLIC;
 
         if (isStatic) {
@@ -165,7 +164,7 @@ public class FunctionNode extends IRNode {
             methodWriter.visitVarInsn(Opcodes.ISTORE, loop.getSlot());
         }
 
-        blockNode.write(classWriter, methodWriter, globals, scopeTable.newScope());
+        blockNode.write(classWriter, methodWriter, scopeTable.newScope());
 
         methodWriter.endMethod();
     }

+ 4 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IRNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
@@ -41,7 +40,7 @@ public abstract class IRNode {
 
     /* end node data */
 
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         throw new UnsupportedOperationException();
     }
 
@@ -49,15 +48,15 @@ public abstract class IRNode {
         throw new UnsupportedOperationException();
     }
 
-    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         throw new UnsupportedOperationException();
     }
 
-    protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         throw new UnsupportedOperationException();
     }
 
-    protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         throw new UnsupportedOperationException();
     }
 }

+ 4 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfElseNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -43,18 +42,18 @@ public class IfElseNode extends ConditionNode {
     /* ---- end tree structure ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
 
         Label fals = new Label();
         Label end = new Label();
 
-        getConditionNode().write(classWriter, methodWriter, globals, scopeTable);
+        getConditionNode().write(classWriter, methodWriter, scopeTable);
         methodWriter.ifZCmp(Opcodes.IFEQ, fals);
 
         getBlockNode().continueLabel = continueLabel;
         getBlockNode().breakLabel = breakLabel;
-        getBlockNode().write(classWriter, methodWriter, globals, scopeTable.newScope());
+        getBlockNode().write(classWriter, methodWriter, scopeTable.newScope());
 
         if (getBlockNode().doAllEscape() == false) {
             methodWriter.goTo(end);
@@ -64,7 +63,7 @@ public class IfElseNode extends ConditionNode {
 
         elseBlockNode.continueLabel = continueLabel;
         elseBlockNode.breakLabel = breakLabel;
-        elseBlockNode.write(classWriter, methodWriter, globals, scopeTable.newScope());
+        elseBlockNode.write(classWriter, methodWriter, scopeTable.newScope());
 
         methodWriter.mark(end);
     }

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/IfNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -29,17 +28,17 @@ import org.objectweb.asm.Opcodes;
 public class IfNode extends ConditionNode {
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
 
         Label fals = new Label();
 
-        getConditionNode().write(classWriter, methodWriter, globals, scopeTable);
+        getConditionNode().write(classWriter, methodWriter, scopeTable);
         methodWriter.ifZCmp(Opcodes.IFEQ, fals);
 
         getBlockNode().continueLabel = continueLabel;
         getBlockNode().breakLabel = breakLabel;
-        getBlockNode().write(classWriter, methodWriter, globals, scopeTable.newScope());
+        getBlockNode().write(classWriter, methodWriter, scopeTable.newScope());
 
         methodWriter.mark(fals);
     }

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

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessLookupUtility;
 import org.elasticsearch.painless.symbol.ScopeTable;
@@ -69,8 +68,8 @@ public class InstanceofNode extends UnaryNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        getChildNode().write(classWriter, methodWriter, globals, scopeTable);
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getChildNode().write(classWriter, methodWriter, scopeTable);
 
         // primitive types
         if (isPrimitiveResult) {

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/LambdaNode.java

@@ -21,7 +21,6 @@ package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
 import org.elasticsearch.painless.FunctionRef;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 import org.elasticsearch.painless.symbol.ScopeTable.Variable;
@@ -56,7 +55,7 @@ public class LambdaNode extends ExpressionNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         if (funcRef != null) {

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListInitializationNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessConstructor;
 import org.elasticsearch.painless.lookup.PainlessMethod;
@@ -54,7 +53,7 @@ public class ListInitializationNode extends ArgumentsNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         methodWriter.newInstance(MethodWriter.getType(getExpressionType()));
@@ -64,7 +63,7 @@ public class ListInitializationNode extends ArgumentsNode {
 
         for (ExpressionNode argument : getArgumentNodes()) {
             methodWriter.dup();
-            argument.write(classWriter, methodWriter, globals, scopeTable);
+            argument.write(classWriter, methodWriter, scopeTable);
             methodWriter.invokeMethodCall(method);
             methodWriter.pop();
         }

+ 7 - 8
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ListSubShortcutNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.WriterConstants;
 import org.elasticsearch.painless.lookup.PainlessMethod;
@@ -54,9 +53,9 @@ public class ListSubShortcutNode extends UnaryNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        setup(classWriter, methodWriter, globals, scopeTable);
-        load(classWriter, methodWriter, globals, scopeTable);
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        setup(classWriter, methodWriter, scopeTable);
+        load(classWriter, methodWriter, scopeTable);
     }
 
     @Override
@@ -65,8 +64,8 @@ public class ListSubShortcutNode extends UnaryNode {
     }
 
     @Override
-    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        getChildNode().write(classWriter, methodWriter, globals, scopeTable);
+    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getChildNode().write(classWriter, methodWriter, scopeTable);
 
         Label noFlip = new Label();
         methodWriter.dup();
@@ -79,7 +78,7 @@ public class ListSubShortcutNode extends UnaryNode {
     }
 
     @Override
-    protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
         methodWriter.invokeMethodCall(getter);
 
@@ -89,7 +88,7 @@ public class ListSubShortcutNode extends UnaryNode {
     }
 
     @Override
-    protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
         methodWriter.invokeMethodCall(setter);
         methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize());

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapInitializationNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessConstructor;
 import org.elasticsearch.painless.lookup.PainlessMethod;
@@ -87,7 +86,7 @@ public class MapInitializationNode extends ExpressionNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         methodWriter.newInstance(MethodWriter.getType(getExpressionType()));
@@ -97,8 +96,8 @@ public class MapInitializationNode extends ExpressionNode {
 
         for (int index = 0; index < getArgumentsSize(); ++index) {
             methodWriter.dup();
-            getKeyNode(index).write(classWriter, methodWriter, globals, scopeTable);
-            getValueNode(index).write(classWriter, methodWriter, globals, scopeTable);
+            getKeyNode(index).write(classWriter, methodWriter, scopeTable);
+            getValueNode(index).write(classWriter, methodWriter, scopeTable);
             methodWriter.invokeMethodCall(method);
             methodWriter.pop();
         }

+ 6 - 7
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MapSubShortcutNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessMethod;
 import org.elasticsearch.painless.symbol.ScopeTable;
@@ -51,8 +50,8 @@ public class MapSubShortcutNode extends UnaryNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        getChildNode().write(classWriter, methodWriter, globals, scopeTable);
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getChildNode().write(classWriter, methodWriter, scopeTable);
 
         methodWriter.writeDebugInfo(location);
         methodWriter.invokeMethodCall(getter);
@@ -68,12 +67,12 @@ public class MapSubShortcutNode extends UnaryNode {
     }
 
     @Override
-    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
-        getChildNode().write(classWriter, methodWriter, globals, scopeTable);
+    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        getChildNode().write(classWriter, methodWriter, scopeTable);
     }
 
     @Override
-    protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void load(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
         methodWriter.invokeMethodCall(getter);
 
@@ -83,7 +82,7 @@ public class MapSubShortcutNode extends UnaryNode {
     }
 
     @Override
-    protected void store(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
         methodWriter.invokeMethodCall(setter);
         methodWriter.writePop(MethodWriter.getType(setter.returnType).getSize());

+ 9 - 10
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MemberCallNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessClassBinding;
 import org.elasticsearch.painless.lookup.PainlessInstanceBinding;
@@ -95,7 +94,7 @@ public class MemberCallNode extends ArgumentsNode {
     /* ---- end node data ---- */
 
     @Override
-    public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    public void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         if (localFunction != null) {
@@ -104,8 +103,8 @@ public class MemberCallNode extends ArgumentsNode {
             }
 
             for (ExpressionNode argumentNode : getArgumentNodes()) {
-                argumentNode.write(classWriter, methodWriter, globals, scopeTable);
-            }
+                argumentNode.write(classWriter, methodWriter, scopeTable);
+           }
 
             if (localFunction.isStatic()) {
                 methodWriter.invokeStatic(CLASS_TYPE, localFunction.getAsmMethod());
@@ -114,8 +113,8 @@ public class MemberCallNode extends ArgumentsNode {
             }
         } else if (importedMethod != null) {
             for (ExpressionNode argumentNode : getArgumentNodes()) {
-                argumentNode.write(classWriter, methodWriter, globals, scopeTable);
-            }
+                argumentNode.write(classWriter, methodWriter, scopeTable);
+           }
 
             methodWriter.invokeStatic(Type.getType(importedMethod.targetClass),
                     new Method(importedMethod.javaMethod.getName(), importedMethod.methodType.toMethodDescriptorString()));
@@ -137,8 +136,8 @@ public class MemberCallNode extends ArgumentsNode {
             }
 
             for (int argument = 0; argument < javaConstructorParameterCount; ++argument) {
-                getArgumentNodes().get(argument).write(classWriter, methodWriter, globals, scopeTable);
-            }
+                getArgumentNodes().get(argument).write(classWriter, methodWriter, scopeTable);
+           }
 
             methodWriter.invokeConstructor(type, Method.getMethod(classBinding.javaConstructor));
             methodWriter.putField(CLASS_TYPE, bindingName, type);
@@ -148,7 +147,7 @@ public class MemberCallNode extends ArgumentsNode {
             methodWriter.getField(CLASS_TYPE, bindingName, type);
 
             for (int argument = 0; argument < classBinding.javaMethod.getParameterCount(); ++argument) {
-                getArgumentNodes().get(argument + javaConstructorParameterCount).write(classWriter, methodWriter, globals, scopeTable);
+                getArgumentNodes().get(argument + javaConstructorParameterCount).write(classWriter, methodWriter, scopeTable);
             }
 
             methodWriter.invokeVirtual(type, Method.getMethod(classBinding.javaMethod));
@@ -159,7 +158,7 @@ public class MemberCallNode extends ArgumentsNode {
             methodWriter.getStatic(CLASS_TYPE, bindingName, type);
 
             for (int argument = 0; argument < instanceBinding.javaMethod.getParameterCount(); ++argument) {
-                getArgumentNodes().get(argument).write(classWriter, methodWriter, globals, scopeTable);
+                getArgumentNodes().get(argument).write(classWriter, methodWriter, scopeTable);
             }
 
             methodWriter.invokeVirtual(type, Method.getMethod(instanceBinding.javaMethod));

+ 6 - 7
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MemberFieldNode.java → modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MemberFieldLoadNode.java

@@ -20,13 +20,16 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 
 import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE;
 
-public class MemberFieldNode extends ExpressionNode {
+/**
+ * Represents reading a value from a member field from
+ * the main class.
+ */
+public class MemberFieldLoadNode extends ExpressionNode {
 
     /* ---- begin node data ---- */
 
@@ -51,12 +54,8 @@ public class MemberFieldNode extends ExpressionNode {
 
     /* ---- end node data ---- */
 
-    public MemberFieldNode() {
-        // do nothing
-    }
-
     @Override
-    public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    public void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         if (isStatic) {

+ 88 - 0
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/MemberFieldStoreNode.java

@@ -0,0 +1,88 @@
+/*
+ * 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.ir;
+
+import org.elasticsearch.painless.ClassWriter;
+import org.elasticsearch.painless.MethodWriter;
+import org.elasticsearch.painless.lookup.PainlessLookupUtility;
+import org.elasticsearch.painless.symbol.ScopeTable;
+
+import static org.elasticsearch.painless.WriterConstants.CLASS_TYPE;
+
+/**
+ * Represents a member field assignment on the main class.
+ * The value to store is generated by the child node accessed
+ * via {@link #getChildNode()}.
+ */
+public class MemberFieldStoreNode extends UnaryNode {
+
+    /* ---- begin node data ---- */
+
+    protected String name;
+    protected Class<?> fieldType;
+    protected boolean isStatic;
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setFieldType(Class<?> fieldType) {
+        this.fieldType = fieldType;
+    }
+
+    public Class<?> getFieldType() {
+        return fieldType;
+    }
+
+    public String getFieldCanonicalTypeName() {
+        return PainlessLookupUtility.typeToCanonicalTypeName(fieldType);
+    }
+
+    public void setStatic(boolean isStatic) {
+        this.isStatic = isStatic;
+    }
+
+    public boolean isStatic() {
+        return isStatic;
+    }
+
+    /* ---- end node data ---- */
+
+    @Override
+    public void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
+        if (isStatic == false) {
+            methodWriter.loadThis();
+        }
+
+        getChildNode().write(classWriter, methodWriter, scopeTable);
+
+        methodWriter.writeDebugInfo(location);
+
+        if (isStatic) {
+            methodWriter.putStatic(CLASS_TYPE, name, MethodWriter.getType(fieldType));
+        } else {
+            methodWriter.putField(CLASS_TYPE, name, MethodWriter.getType(fieldType));
+        }
+    }
+}

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayFuncRefNode.java

@@ -21,7 +21,6 @@ package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
 import org.elasticsearch.painless.FunctionRef;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 
@@ -42,7 +41,7 @@ public class NewArrayFuncRefNode extends ExpressionNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         if (funcRef != null) {
             methodWriter.writeDebugInfo(location);
             methodWriter.invokeLambdaCall(funcRef);

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewArrayNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 
@@ -41,7 +40,7 @@ public class NewArrayNode extends ArgumentsNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         if (initialize) {
@@ -53,12 +52,12 @@ public class NewArrayNode extends ArgumentsNode {
 
                 methodWriter.dup();
                 methodWriter.push(index);
-                argumentNode.write(classWriter, methodWriter, globals, scopeTable);
+                argumentNode.write(classWriter, methodWriter, scopeTable);
                 methodWriter.arrayStore(MethodWriter.getType(getExpressionType().getComponentType()));
             }
         } else {
             for (ExpressionNode argumentNode : getArgumentNodes()) {
-                argumentNode.write(classWriter, methodWriter, globals, scopeTable);
+                argumentNode.write(classWriter, methodWriter, scopeTable);
             }
 
             if (getArgumentNodes().size() > 1) {

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NewObjectNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.lookup.PainlessConstructor;
 import org.elasticsearch.painless.symbol.ScopeTable;
@@ -53,7 +52,7 @@ public final class NewObjectNode extends ArgumentsNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         methodWriter.newInstance(MethodWriter.getType(getExpressionType()));
@@ -63,7 +62,7 @@ public final class NewObjectNode extends ArgumentsNode {
         }
 
         for (ExpressionNode argumentNode : getArgumentNodes()) {
-            argumentNode.write(classWriter, methodWriter, globals, scopeTable);
+            argumentNode.write(classWriter, methodWriter, scopeTable);
         }
 
         methodWriter.invokeConstructor(

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -28,7 +27,7 @@ import org.objectweb.asm.Opcodes;
 public class NullNode extends ExpressionNode {
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.visitInsn(Opcodes.ACONST_NULL);
     }
 }

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/NullSafeSubNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -28,13 +27,13 @@ import org.objectweb.asm.Label;
 public class NullSafeSubNode extends UnaryNode {
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         Label end = new Label();
         methodWriter.dup();
         methodWriter.ifNull(end);
-        getChildNode().write(classWriter, methodWriter, globals, scopeTable);
+        getChildNode().write(classWriter, methodWriter, scopeTable);
         methodWriter.mark(end);
     }
 }

+ 0 - 93
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/RegexNode.java

@@ -1,93 +0,0 @@
-/*
- * 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.ir;
-
-import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Constant;
-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;
-
-public class RegexNode extends ExpressionNode {
-
-    /* ---- begin node data ---- */
-
-    private String pattern;
-    private int flags;
-    private Constant constant;
-
-    public void setPattern(String pattern) {
-        this.pattern = pattern;
-    }
-
-    public String getPattern() {
-        return pattern;
-    }
-
-    public void setFlags(int flags) {
-        this.flags = flags;
-    }
-
-    public int getFlags() {
-        return flags;
-    }
-
-    public void setConstant(Constant constant) {
-        this.constant = constant;
-    }
-
-    public Object getConstant() {
-        return constant;
-    }
-
-    /* ---- end node data ---- */
-
-    @Override
-    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));
-        globals.addConstantInitializer(constant);
-    }
-
-    public void initializeConstant(MethodWriter writer) {
-        writer.push(pattern);
-        writer.push(flags);
-        writer.invokeStatic(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_COMPILE);
-    }
-
-    protected int flagForChar(char c) {
-        switch (c) {
-            case 'c': return Pattern.CANON_EQ;
-            case 'i': return Pattern.CASE_INSENSITIVE;
-            case 'l': return Pattern.LITERAL;
-            case 'm': return Pattern.MULTILINE;
-            case 's': return Pattern.DOTALL;
-            case 'U': return Pattern.UNICODE_CHARACTER_CLASS;
-            case 'u': return Pattern.UNICODE_CASE;
-            case 'x': return Pattern.COMMENTS;
-            default:
-                throw new IllegalArgumentException("Unknown flag [" + c + "]");
-        }
-    }
-}

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ReturnNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 
@@ -41,11 +40,11 @@ public class ReturnNode extends StatementNode {
     /* ---- end tree structure ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
 
         if (expressionNode != null) {
-            expressionNode.write(classWriter, methodWriter, globals, scopeTable);
+            expressionNode.write(classWriter, methodWriter, scopeTable);
         }
 
         methodWriter.returnValue();

+ 4 - 22
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StatementExpressionNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 
@@ -38,29 +37,12 @@ public class StatementExpressionNode extends StatementNode {
         return expressionNode;
     }
 
-    /* ---- end tree structure, begin node data ---- */
-
-    private boolean methodEscape;
-
-    public void setMethodEscape(boolean methodEscape) {
-        this.methodEscape = methodEscape;
-    }
-
-    public boolean getMethodEscape() {
-        return methodEscape;
-    }
-
-    /* ---- end node data ---- */
+    /* ---- end tree structure ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
-        expressionNode.write(classWriter, methodWriter, globals, scopeTable);
-
-        if (methodEscape) {
-            methodWriter.returnValue();
-        } else {
-            methodWriter.writePop(MethodWriter.getType(expressionNode.getExpressionType()).getSize());
-        }
+        expressionNode.write(classWriter, methodWriter, scopeTable);
+        methodWriter.writePop(MethodWriter.getType(expressionNode.getExpressionType()).getSize());
     }
 }

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/StaticNode.java

@@ -20,14 +20,13 @@
 package org.elasticsearch.painless.ir;
 
 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, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         // do nothing
     }
 }

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/ThrowNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.symbol.ScopeTable;
 
@@ -41,9 +40,9 @@ public class ThrowNode extends StatementNode {
     /* ---- end tree structure ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
-        expressionNode.write(classWriter, methodWriter, globals, scopeTable);
+        expressionNode.write(classWriter, methodWriter, scopeTable);
         methodWriter.throwException();
     }
 }

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/TryNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -54,7 +53,7 @@ public class TryNode extends StatementNode {
     /* ---- end tree structure ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
 
         Label begin = new Label();
@@ -65,7 +64,7 @@ public class TryNode extends StatementNode {
 
         blockNode.continueLabel = continueLabel;
         blockNode.breakLabel = breakLabel;
-        blockNode.write(classWriter, methodWriter, globals, scopeTable.newScope());
+        blockNode.write(classWriter, methodWriter, scopeTable.newScope());
 
         if (blockNode.doAllEscape() == false) {
             methodWriter.goTo(exception);
@@ -77,7 +76,7 @@ public class TryNode extends StatementNode {
             catchNode.begin = begin;
             catchNode.end = end;
             catchNode.exception = catchNodes.size() > 1 ? exception : null;
-            catchNode.write(classWriter, methodWriter, globals, scopeTable.newScope());
+            catchNode.write(classWriter, methodWriter, scopeTable.newScope());
         }
 
         if (blockNode.doAllEscape() == false || catchNodes.size() > 1) {

+ 4 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/UnaryMathNode.java

@@ -21,7 +21,6 @@ package org.elasticsearch.painless.ir;
 
 import org.elasticsearch.painless.ClassWriter;
 import org.elasticsearch.painless.DefBootstrap;
-import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.Operation;
 import org.elasticsearch.painless.lookup.PainlessLookupUtility;
@@ -79,14 +78,15 @@ public class UnaryMathNode extends UnaryNode {
     /* ---- end node data ---- */
 
     @Override
-    public void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    public void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeDebugInfo(location);
 
         if (operation == Operation.NOT) {
             Label fals = new Label();
             Label end = new Label();
 
-            getChildNode().write(classWriter, methodWriter, globals, scopeTable);
+            getChildNode().write(classWriter, methodWriter, scopeTable);
+
             methodWriter.ifZCmp(Opcodes.IFEQ, fals);
 
             methodWriter.push(false);
@@ -95,7 +95,7 @@ public class UnaryMathNode extends UnaryNode {
             methodWriter.push(true);
             methodWriter.mark(end);
         } else {
-            getChildNode().write(classWriter, methodWriter, globals, scopeTable);
+            getChildNode().write(classWriter, methodWriter, 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.

+ 4 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/VariableNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -43,7 +42,7 @@ public class VariableNode extends ExpressionNode {
     /* ---- end node data ---- */
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         Variable variable = scopeTable.getVariable(name);
         methodWriter.visitVarInsn(variable.getAsmType().getOpcode(Opcodes.ILOAD), variable.getSlot());
     }
@@ -54,18 +53,18 @@ public class VariableNode extends ExpressionNode {
     }
 
     @Override
-    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void setup(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         // do nothing
     }
 
     @Override
-    protected void load(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void load(ClassWriter classWriter, MethodWriter methodWriter, 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, ScopeTable scopeTable) {
+    protected void store(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         Variable variable = scopeTable.getVariable(name);
         methodWriter.visitVarInsn(variable.getAsmType().getOpcode(Opcodes.ISTORE), variable.getSlot());
     }

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/ir/WhileNode.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.ir;
 
 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;
@@ -30,7 +29,7 @@ import org.objectweb.asm.Opcodes;
 public class WhileNode extends LoopNode {
 
     @Override
-    protected void write(ClassWriter classWriter, MethodWriter methodWriter, Globals globals, ScopeTable scopeTable) {
+    protected void write(ClassWriter classWriter, MethodWriter methodWriter, ScopeTable scopeTable) {
         methodWriter.writeStatementOffset(location);
 
         scopeTable = scopeTable.newScope();
@@ -41,7 +40,7 @@ public class WhileNode extends LoopNode {
         methodWriter.mark(begin);
 
         if (isContinuous() == false) {
-            getConditionNode().write(classWriter, methodWriter, globals, scopeTable);
+            getConditionNode().write(classWriter, methodWriter, scopeTable);
             methodWriter.ifZCmp(Opcodes.IFEQ, end);
         }
 
@@ -54,7 +53,7 @@ public class WhileNode extends LoopNode {
 
             getBlockNode().continueLabel = begin;
             getBlockNode().breakLabel = end;
-            getBlockNode().write(classWriter, methodWriter, globals, scopeTable);
+            getBlockNode().write(classWriter, methodWriter, scopeTable);
         } else {
             Variable loop = scopeTable.getInternalVariable("loop");
 

+ 88 - 22
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java

@@ -19,16 +19,23 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Constant;
 import org.elasticsearch.painless.Location;
-import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.Scope;
-import org.elasticsearch.painless.WriterConstants;
+import org.elasticsearch.painless.ir.BlockNode;
+import org.elasticsearch.painless.ir.CallNode;
+import org.elasticsearch.painless.ir.CallSubNode;
 import org.elasticsearch.painless.ir.ClassNode;
-import org.elasticsearch.painless.ir.RegexNode;
+import org.elasticsearch.painless.ir.ConstantNode;
+import org.elasticsearch.painless.ir.FieldNode;
+import org.elasticsearch.painless.ir.MemberFieldLoadNode;
+import org.elasticsearch.painless.ir.MemberFieldStoreNode;
+import org.elasticsearch.painless.ir.StatementExpressionNode;
+import org.elasticsearch.painless.ir.StaticNode;
+import org.elasticsearch.painless.lookup.PainlessMethod;
 import org.elasticsearch.painless.symbol.ScriptRoot;
 
 import java.lang.reflect.Modifier;
+import java.util.Arrays;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
 
@@ -39,7 +46,7 @@ public final class ERegex extends AExpression {
 
     private final String pattern;
     private final int flags;
-    private Constant constant;
+    private String name;
 
     public ERegex(Location location, String pattern, String flagsString) {
         super(location);
@@ -74,30 +81,89 @@ public final class ERegex extends AExpression {
                     new IllegalArgumentException("Error compiling regex: " + e.getDescription()));
         }
 
-        String name = scriptRoot.getNextSyntheticName("regex");
-        scriptRoot.getClassNode().addField(
-                new SField(location, Modifier.FINAL | Modifier.STATIC | Modifier.PRIVATE, name, Pattern.class));
-        constant = new Constant(location, MethodWriter.getType(Pattern.class), name, this::initializeConstant);
+        name = scriptRoot.getNextSyntheticName("regex");
         actual = Pattern.class;
     }
 
     @Override
-    RegexNode write(ClassNode classNode) {
-        RegexNode regexNode = new RegexNode();
-        regexNode.setLocation(location);
+    MemberFieldLoadNode write(ClassNode classNode) {
+        FieldNode fieldNode = new FieldNode();
+        fieldNode.setLocation(location);
+        fieldNode.setModifiers(Modifier.FINAL | Modifier.STATIC | Modifier.PRIVATE);
+        fieldNode.setFieldType(Pattern.class);
+        fieldNode.setName(name);
 
-        regexNode.setExpressionType(actual);
-        regexNode.setFlags(flags);
-        regexNode.setPattern(pattern);
-        regexNode.setConstant(constant);
+        classNode.addFieldNode(fieldNode);
 
-        return regexNode;
-    }
+        try {
+            StatementExpressionNode statementExpressionNode = new StatementExpressionNode();
+            statementExpressionNode.setLocation(location);
+
+            BlockNode blockNode = classNode.getClinitBlockNode();
+            blockNode.addStatementNode(statementExpressionNode);
+
+            MemberFieldStoreNode memberFieldStoreNode = new MemberFieldStoreNode();
+            memberFieldStoreNode.setLocation(location);
+            memberFieldStoreNode.setExpressionType(void.class);
+            memberFieldStoreNode.setFieldType(Pattern.class);
+            memberFieldStoreNode.setName(name);
+            memberFieldStoreNode.setStatic(true);
+
+            statementExpressionNode.setExpressionNode(memberFieldStoreNode);
+
+            CallNode callNode = new CallNode();
+            callNode.setLocation(location);
+            callNode.setExpressionType(Pattern.class);
+
+            memberFieldStoreNode.setChildNode(callNode);
+
+            StaticNode staticNode = new StaticNode();
+            staticNode.setLocation(location);
+            staticNode.setExpressionType(Pattern.class);
+
+            callNode.setLeftNode(staticNode);
+
+            CallSubNode callSubNode = new CallSubNode();
+            callSubNode.setLocation(location);
+            callSubNode.setExpressionType(Pattern.class);
+            callSubNode.setBox(Pattern.class);
+            callSubNode.setMethod(new PainlessMethod(
+                    Pattern.class.getMethod("compile", String.class, int.class),
+                    Pattern.class,
+                    Pattern.class,
+                    Arrays.asList(String.class, int.class),
+                    null,
+                    null,
+                    null
+                    )
+            );
+
+            callNode.setRightNode(callSubNode);
+
+            ConstantNode constantNode = new ConstantNode();
+            constantNode.setLocation(location);
+            constantNode.setExpressionType(String.class);
+            constantNode.setConstant(pattern);
+
+            callSubNode.addArgumentNode(constantNode);
+
+            constantNode = new ConstantNode();
+            constantNode.setLocation(location);
+            constantNode.setExpressionType(int.class);
+            constantNode.setConstant(flags);
+
+            callSubNode.addArgumentNode(constantNode);
+        } catch (Exception exception) {
+            throw createError(new IllegalStateException("could not generate regex constant [" + pattern + "/" + flags +"] in clinit"));
+        }
+
+        MemberFieldLoadNode memberFieldLoadNode = new MemberFieldLoadNode();
+        memberFieldLoadNode.setLocation(location);
+        memberFieldLoadNode.setExpressionType(Pattern.class);
+        memberFieldLoadNode.setName(name);
+        memberFieldLoadNode.setStatic(true);
 
-    private void initializeConstant(MethodWriter writer) {
-        writer.push(pattern);
-        writer.push(flags);
-        writer.invokeStatic(org.objectweb.asm.Type.getType(Pattern.class), WriterConstants.PATTERN_COMPILE);
+        return memberFieldLoadNode;
     }
 
     private int flagForChar(char c) {

+ 18 - 7
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java

@@ -22,7 +22,9 @@ package org.elasticsearch.painless.node;
 import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.Scope;
 import org.elasticsearch.painless.ir.ClassNode;
+import org.elasticsearch.painless.ir.ReturnNode;
 import org.elasticsearch.painless.ir.StatementExpressionNode;
+import org.elasticsearch.painless.ir.StatementNode;
 import org.elasticsearch.painless.symbol.ScriptRoot;
 
 import java.util.Objects;
@@ -48,7 +50,7 @@ public final class SExpression extends AStatement {
         expression.read = lastSource && !isVoid;
         expression.analyze(scriptRoot, scope);
 
-        if (!lastSource && !expression.statement) {
+        if ((lastSource == false || isVoid) && expression.statement == false) {
             throw createError(new IllegalArgumentException("Not a statement."));
         }
 
@@ -65,15 +67,24 @@ public final class SExpression extends AStatement {
     }
 
     @Override
-    StatementExpressionNode write(ClassNode classNode) {
-        StatementExpressionNode statementExpressionNode = new StatementExpressionNode();
+    StatementNode write(ClassNode classNode) {
+        if (methodEscape) {
+            ReturnNode returnNode = new ReturnNode();
 
-        statementExpressionNode.setExpressionNode(expression.write(classNode));
+            returnNode.setExpressionNode(expression.write(classNode));
 
-        statementExpressionNode.setLocation(location);
-        statementExpressionNode.setMethodEscape(methodEscape);
+            returnNode.setLocation(location);
 
-        return statementExpressionNode;
+            return returnNode;
+        } else {
+            StatementExpressionNode statementExpressionNode = new StatementExpressionNode();
+
+            statementExpressionNode.setExpressionNode(expression.write(classNode));
+
+            statementExpressionNode.setLocation(location);
+
+            return statementExpressionNode;
+        }
     }
 
     @Override

+ 19 - 0
modules/lang-painless/src/test/java/org/elasticsearch/painless/FactoryTests.java

@@ -38,6 +38,7 @@ public class FactoryTests extends ScriptTestCase {
         contexts.put(DeterministicFactoryTestScript.CONTEXT, Whitelist.BASE_WHITELISTS);
         contexts.put(EmptyTestScript.CONTEXT, Whitelist.BASE_WHITELISTS);
         contexts.put(TemplateScript.CONTEXT, Whitelist.BASE_WHITELISTS);
+        contexts.put(VoidReturnTestScript.CONTEXT, Whitelist.BASE_WHITELISTS);
 
         return contexts;
     }
@@ -255,4 +256,22 @@ public class FactoryTests extends ScriptTestCase {
         FactoryTestScript script = factory.newInstance(Collections.singletonMap("x", 1));
         assertEquals(2, script.execute(1));
     }
+
+    public abstract static class VoidReturnTestScript {
+        public static final String[] PARAMETERS = {"map"};
+        public abstract void execute(Map<Object, Object> map);
+
+        public interface Factory {
+            VoidReturnTestScript newInstance();
+        }
+
+        public static final ScriptContext<VoidReturnTestScript.Factory> CONTEXT =
+                new ScriptContext<>("test", VoidReturnTestScript.Factory.class);
+    }
+
+    public void testVoidReturn() {
+        IllegalArgumentException iae = expectScriptThrows(IllegalArgumentException.class, () ->
+                scriptEngine.compile("void_return_test", "1 + 1", VoidReturnTestScript.CONTEXT, Collections.emptyMap()));
+        assertEquals(iae.getMessage(), "Not a statement.");
+    }
 }