You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2019/11/26 22:44:47 UTC

[groovy] branch master updated: refactor InvocationWriter to reduce duplication around makeCall

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new b56d1c1  refactor InvocationWriter to reduce duplication around makeCall
b56d1c1 is described below

commit b56d1c17cc48f024d500688d4b2a8ca4a609f1cd
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Nov 26 16:36:17 2019 -0600

    refactor InvocationWriter to reduce duplication around makeCall
    
    - replace usesSuper with AsmClassGenerator#isSuperExpression
    
    - handling of "this" and "super" was a bit spread around
---
 .../groovy/classgen/AsmClassGenerator.java         |   2 +-
 .../groovy/classgen/asm/InvocationWriter.java      | 401 ++++++++-------------
 .../classgen/asm/sc/StaticInvocationWriter.java    |  13 +-
 3 files changed, 164 insertions(+), 252 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index 717c735..8123d66 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -2132,7 +2132,7 @@ public class AsmClassGenerator extends ClassGenerator {
         return expression instanceof VariableExpression && ((VariableExpression) expression).isThisExpression();
     }
 
-    private static boolean isSuperExpression(final Expression expression) {
+    public static boolean isSuperExpression(final Expression expression) {
         return expression instanceof VariableExpression && ((VariableExpression) expression).isSuperExpression();
     }
 
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
index 123f38b..71fef6c 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
@@ -22,7 +22,6 @@ import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.FieldNode;
-import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
@@ -40,7 +39,6 @@ import org.codehaus.groovy.ast.expr.TupleExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.ast.tools.WideningCategories;
 import org.codehaus.groovy.classgen.AsmClassGenerator;
-import org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.StatementMeta;
 import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
 import org.codehaus.groovy.runtime.typehandling.ShortTypeHandling;
@@ -50,7 +48,6 @@ import org.objectweb.asm.MethodVisitor;
 
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -82,64 +79,43 @@ public class InvocationWriter {
     public static final MethodCallerMultiAdapter invokeStaticMethod = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "invokeStaticMethod", true, true);
     public static final MethodCaller invokeClosureMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeClosure");
     public static final MethodCaller castToVargsArray = MethodCaller.newStatic(DefaultTypeTransformation.class, "castToVargsArray");
-    private static final MethodNode CLASS_FOR_NAME_STRING = ClassHelper.CLASS_Type.getDeclaredMethod("forName", new Parameter[]{new Parameter(ClassHelper.STRING_TYPE,"name")});
+    private static final MethodNode CLASS_FOR_NAME_STRING = ClassHelper.CLASS_Type.getDeclaredMethod("forName", new Parameter[]{new Parameter(ClassHelper.STRING_TYPE, "name")});
 
     // type conversions
-    private static final MethodCaller
-        asTypeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "asType"),
-        castToTypeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "castToType"),
-        castToClassMethod = MethodCaller.newStatic(ShortTypeHandling.class, "castToClass"),
-        castToStringMethod = MethodCaller.newStatic(ShortTypeHandling.class, "castToString"),
-        castToEnumMethod = MethodCaller.newStatic(ShortTypeHandling.class, "castToEnum");
+    private static final MethodCaller asTypeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "asType");
+    private static final MethodCaller castToTypeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "castToType");
+    private static final MethodCaller castToClassMethod = MethodCaller.newStatic(ShortTypeHandling.class, "castToClass");
+    private static final MethodCaller castToStringMethod = MethodCaller.newStatic(ShortTypeHandling.class, "castToString");
+    private static final MethodCaller castToEnumMethod = MethodCaller.newStatic(ShortTypeHandling.class, "castToEnum");
 
     // constructor calls with this() and super()
-    static final MethodCaller selectConstructorAndTransformArguments = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "selectConstructorAndTransformArguments");
+    private static final MethodCaller selectConstructorAndTransformArguments = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "selectConstructorAndTransformArguments");
 
     private final WriterController controller;
-    
-    public InvocationWriter(WriterController wc) {
-        this.controller = wc;
+
+    public InvocationWriter(final WriterController controller) {
+        this.controller = controller;
     }
 
-    private void makeInvokeMethodCall(MethodCallExpression call, boolean useSuper, MethodCallerMultiAdapter adapter) {
-        // receiver
-        // we operate on GroovyObject if possible
-        Expression objectExpression = call.getObjectExpression();
-        // message name
-        Expression messageName = new CastExpression(ClassHelper.STRING_TYPE, call.getMethod());
-        if (useSuper) {
-            ClassNode classNode = controller.isInClosure() ? controller.getOutermostClass() : controller.getClassNode(); // GROOVY-4035 
-            ClassNode superClass = classNode.getSuperClass();
-            makeCall(call, new ClassExpression(superClass),
-                    objectExpression, messageName,
-                    call.getArguments(), adapter,
-                    call.isSafe(), call.isSpreadSafe(),
-                    false
-            );
-        } else {
-            makeCall(call, objectExpression, messageName,
-                    call.getArguments(), adapter,
-                    call.isSafe(), call.isSpreadSafe(),
-                    call.isImplicitThis()
-            );
+    public void makeCall(final Expression origin, final Expression receiver, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, boolean safe, final boolean spreadSafe, boolean implicitThis) {
+        ClassNode sender = controller.getClassNode();
+        if (AsmClassGenerator.isSuperExpression(receiver) || (AsmClassGenerator.isThisExpression(receiver) && !implicitThis)) {
+            while (sender.isDerivedFrom(ClassHelper.CLOSURE_TYPE) && sender.implementsInterface(ClassHelper.GENERATED_CLOSURE_Type)) {
+                sender = sender.getOuterClass();
+            }
+            if (AsmClassGenerator.isSuperExpression(receiver)) {
+                sender = sender.getSuperClass(); // GROOVY-4035
+                implicitThis = false; // prevent recursion
+                safe = false; // GROOVY-6045
+            }
         }
+
+        makeCall(origin, new ClassExpression(sender), receiver, message, arguments, adapter, safe, spreadSafe, implicitThis);
     }
-    
-    public void makeCall(
-            Expression origin,
-            Expression receiver, Expression message, Expression arguments,
-            MethodCallerMultiAdapter adapter,
-            boolean safe, boolean spreadSafe, boolean implicitThis
-    ) {
-        ClassNode cn = controller.getClassNode();
-        if (controller.isInClosure() && !implicitThis && AsmClassGenerator.isThisExpression(receiver)) cn=cn.getOuterClass();
-        makeCall(origin, new ClassExpression(cn), receiver, message, arguments,
-                adapter, safe, spreadSafe, implicitThis);
-    }
-    
-    protected boolean writeDirectMethodCall(MethodNode target, boolean implicitThis,  Expression receiver, TupleExpression args) {
-        if (target==null) return false;
-        
+
+    protected boolean writeDirectMethodCall(final MethodNode target, final boolean implicitThis, final Expression receiver, final TupleExpression args) {
+        if (target == null) return false;
+
         String methodName = target.getName();
         CompileStack compileStack = controller.getCompileStack();
         OperandStack operandStack = controller.getOperandStack();
@@ -152,20 +128,20 @@ public class InvocationWriter {
             opcode = INVOKESTATIC;
         } else if (declaringClass.isInterface()) {
             opcode = INVOKEINTERFACE;
-        } else if (target.isPrivate() || ((receiver instanceof VariableExpression && ((VariableExpression) receiver).isSuperExpression()))) {
+        } else if (target.isPrivate() || AsmClassGenerator.isSuperExpression(receiver)) {
             opcode = INVOKESPECIAL;
         }
 
         // handle receiver
         int argumentsToRemove = 0;
-        if (opcode!=INVOKESTATIC) {
-            if (receiver!=null) {
+        if (opcode != INVOKESTATIC) {
+            if (receiver != null) {
                 // load receiver if not static invocation
                 // todo: fix inner class case
                 if (implicitThis
+                        && classNode.getOuterClass() != null
                         && !classNode.isDerivedFrom(declaringClass)
-                        && !classNode.implementsInterface(declaringClass)
-                        && classNode instanceof InnerClassNode) {
+                        && !classNode.implementsInterface(declaringClass)) {
                     // we are calling an outer class method
                     compileStack.pushImplicitThis(false);
                     if (controller.isInClosure()) {
@@ -180,18 +156,18 @@ public class InvocationWriter {
                 }
                 operandStack.doGroovyCast(declaringClass);
                 compileStack.popImplicitThis();
-                argumentsToRemove++;
+                argumentsToRemove += 1;
             } else {
                 mv.visitIntInsn(ALOAD,0);
                 operandStack.push(classNode);
-                argumentsToRemove++;
+                argumentsToRemove += 1;
             }
         }
 
         int stackSize = operandStack.getStackLength();
 
         String owner = BytecodeHelper.getClassInternalName(declaringClass);
-        ClassNode receiverType = receiver!=null?controller.getTypeChooser().resolveType(receiver, classNode):declaringClass;
+        ClassNode receiverType = receiver != null ? controller.getTypeChooser().resolveType(receiver, classNode) : declaringClass;
         if (opcode == INVOKEVIRTUAL && ClassHelper.OBJECT_TYPE.equals(declaringClass)) {
             // avoid using a narrowed type if the method is defined on object because it can interfere
             // with delegate type inference in static compilation mode and trigger a ClassCastException
@@ -215,8 +191,7 @@ public class InvocationWriter {
                     && !receiverType.equals(declaringClass))
                     && receiverType.isDerivedFrom(declaringClass)
                     && !receiverType.getPackageName().equals(classNode.getPackageName())) {
-                // package private class, public method
-                // see GROOVY-6962
+                // GROOVY-6962: package private class, public method
                 owner = BytecodeHelper.getClassInternalName(receiverType);
             }
         }
@@ -226,7 +201,7 @@ public class InvocationWriter {
         String desc = BytecodeHelper.getMethodDescriptor(target.getReturnType(), target.getParameters());
         mv.visitMethodInsn(opcode, owner, methodName, desc, declaringClass.isInterface());
         ClassNode ret = target.getReturnType().redirect();
-        if (ret==ClassHelper.VOID_TYPE) {
+        if (ret == ClassHelper.VOID_TYPE) {
             ret = ClassHelper.OBJECT_TYPE;
             mv.visitInsn(ACONST_NULL);
         }
@@ -236,33 +211,32 @@ public class InvocationWriter {
         return true;
     }
 
-    private boolean lastIsArray(List<Expression> argumentList, int pos) {
+    private boolean lastIsArray(final List<Expression> argumentList, final int pos) {
         Expression last = argumentList.get(pos);
         ClassNode type = controller.getTypeChooser().resolveType(last, controller.getClassNode());
         return type.isArray();
     }
-    
+
     // load arguments
-    protected void loadArguments(List<Expression> argumentList, Parameter[] para) {
-        if (para.length==0) return;
+    protected void loadArguments(final List<Expression> argumentList, final Parameter[] para) {
+        if (para.length == 0) return;
         ClassNode lastParaType = para[para.length - 1].getOriginType();
         AsmClassGenerator acg = controller.getAcg();
         OperandStack operandStack = controller.getOperandStack();
-        if (lastParaType.isArray()
-                && (argumentList.size()>para.length || argumentList.size()==para.length-1 || !lastIsArray(argumentList, para.length-1))) {
-            int stackLen = operandStack.getStackLength()+argumentList.size();
+        if (lastParaType.isArray() && (argumentList.size() > para.length
+                || argumentList.size() == para.length - 1 || !lastIsArray(argumentList, para.length - 1))) {
+            int stackLen = operandStack.getStackLength() + argumentList.size();
             MethodVisitor mv = controller.getMethodVisitor();
-            //mv = new org.objectweb.asm.util.TraceMethodVisitor(mv);
             controller.setMethodVisitor(mv);
             // varg call
             // first parameters as usual
-            for (int i = 0; i < para.length-1; i++) {
+            for (int i = 0, n = para.length - 1; i < n; i += 1) {
                 argumentList.get(i).visit(acg);
                 operandStack.doGroovyCast(para[i].getType());
             }
             // last parameters wrapped in an array
-            List<Expression> lastParams = new LinkedList<Expression>();
-            for (int i=para.length-1; i<argumentList.size();i++) {
+            List<Expression> lastParams = new LinkedList<>();
+            for (int i = para.length - 1, n = argumentList.size(); i < n; i += 1) {
                 lastParams.add(argumentList.get(i));
             }
             ArrayExpression array = new ArrayExpression(
@@ -271,31 +245,25 @@ public class InvocationWriter {
             );
             array.visit(acg);
             // adjust stack length
-            while (operandStack.getStackLength()<stackLen) {
+            while (operandStack.getStackLength() < stackLen) {
                 operandStack.push(ClassHelper.OBJECT_TYPE);
             }
-            if (argumentList.size()==para.length-1) {
+            if (argumentList.size() == para.length - 1) {
                 operandStack.remove(1);
             }
         } else {
-            for (int i = 0; i < argumentList.size(); i++) {
+            for (int i = 0, n = argumentList.size(); i < n; i += 1) {
                 argumentList.get(i).visit(acg);
                 operandStack.doGroovyCast(para[i].getType());
             }
         }
     }
 
-    protected boolean makeDirectCall(
-        Expression origin, Expression receiver, 
-        Expression message, Expression arguments,
-        MethodCallerMultiAdapter adapter,
-        boolean implicitThis, boolean containsSpreadExpression
-    ) {
+    protected boolean makeDirectCall(Expression origin, Expression receiver, Expression message, Expression arguments, MethodCallerMultiAdapter adapter, boolean implicitThis, boolean containsSpreadExpression) {
         if (makeClassForNameCall(origin, receiver, message, arguments)) return true;
 
         // optimization path
-        boolean fittingAdapter =   adapter == invokeMethodOnCurrent ||
-                                    adapter == invokeStaticMethod;
+        boolean fittingAdapter = adapter == invokeMethodOnCurrent || adapter == invokeStaticMethod;
         if (fittingAdapter && controller.optimizeForInt && controller.isFastPath()) {
             String methodName = getMethodName(message);
             if (methodName != null) {
@@ -306,10 +274,10 @@ public class InvocationWriter {
                     args = new TupleExpression(receiver);
                 }
 
-                StatementMeta meta = null;
-                if (origin!=null) meta = origin.getNodeMetaData(StatementMeta.class);
+                OptimizingStatementWriter.StatementMeta meta = null;
+                if (origin != null) meta = origin.getNodeMetaData(OptimizingStatementWriter.StatementMeta.class);
                 MethodNode mn = null;
-                if (meta!=null) mn = meta.target;
+                if (meta != null) mn = meta.target;
 
                 if (writeDirectMethodCall(mn, true, null, args)) return true;
             }
@@ -324,39 +292,23 @@ public class InvocationWriter {
         return false;
     }
 
-    protected boolean makeCachedCall(
-            Expression origin, ClassExpression sender,
-            Expression receiver, Expression message, Expression arguments,
-            MethodCallerMultiAdapter adapter,
-            boolean safe, boolean spreadSafe, boolean implicitThis,
-            boolean containsSpreadExpression
-    ) {
+    protected boolean makeCachedCall(Expression origin, ClassExpression sender, Expression receiver, Expression message, Expression arguments, MethodCallerMultiAdapter adapter, boolean safe, boolean spreadSafe, boolean implicitThis, boolean containsSpreadExpression) {
         // prepare call site
         if ((adapter == invokeMethod || adapter == invokeMethodOnCurrent || adapter == invokeStaticMethod) && !spreadSafe) {
             String methodName = getMethodName(message);
-
             if (methodName != null) {
-                controller.getCallSiteWriter().makeCallSite(
-                        receiver, methodName, arguments, safe, implicitThis, 
-                        adapter == invokeMethodOnCurrent, 
-                        adapter == invokeStaticMethod);
+                controller.getCallSiteWriter().makeCallSite(receiver, methodName, arguments, safe, implicitThis, adapter == invokeMethodOnCurrent, adapter == invokeStaticMethod);
                 return true;
             }
         }
         return false;
     }
-    
-    protected void makeUncachedCall(
-            Expression origin, ClassExpression sender,
-            Expression receiver, Expression message, Expression arguments,
-            MethodCallerMultiAdapter adapter,
-            boolean safe, boolean spreadSafe, boolean implicitThis,
-            boolean containsSpreadExpression
-    ) {
+
+    protected void makeUncachedCall(Expression origin, ClassExpression sender, Expression receiver, Expression message, Expression arguments, MethodCallerMultiAdapter adapter, boolean safe, boolean spreadSafe, boolean implicitThis, boolean containsSpreadExpression) {
         OperandStack operandStack = controller.getOperandStack();
         CompileStack compileStack = controller.getCompileStack();
         AsmClassGenerator acg = controller.getAcg();
-        
+
         // ensure VariableArguments are read, not stored
         compileStack.pushLHS(false);
 
@@ -371,20 +323,19 @@ public class InvocationWriter {
         if (adapter == invokeMethodOnSuper && methodName != null) {
             controller.getSuperMethodNames().add(methodName);
         }
-        
+
         // receiver
         compileStack.pushImplicitThis(implicitThis);
         receiver.visit(acg);
         operandStack.box();
         compileStack.popImplicitThis();
-        
-        
+
         int operandsToRemove = 2;
         // message
         if (message != null) {
             message.visit(acg);
             operandStack.box();
-            operandsToRemove++;
+            operandsToRemove += 1;
         }
 
         // arguments
@@ -399,7 +350,7 @@ public class InvocationWriter {
         } else if (numberOfArguments > 0) {
             operandsToRemove += numberOfArguments;
             TupleExpression te = (TupleExpression) arguments;
-            for (int i = 0; i < numberOfArguments; i++) {
+            for (int i = 0; i < numberOfArguments; i += 1) {
                 Expression argument = te.getExpression(i);
                 argument.visit(acg);
                 operandStack.box();
@@ -407,19 +358,14 @@ public class InvocationWriter {
             }
         }
 
-        if (adapter==null) adapter = invokeMethod;
+        if (adapter == null) adapter = invokeMethod;
         adapter.call(controller.getMethodVisitor(), numberOfArguments, safe, spreadSafe);
 
         compileStack.popLHS();
-        operandStack.replace(ClassHelper.OBJECT_TYPE,operandsToRemove);
-    }
-    
-    protected void makeCall(
-            Expression origin, ClassExpression sender,
-            Expression receiver, Expression message, Expression arguments,
-            MethodCallerMultiAdapter adapter,
-            boolean safe, boolean spreadSafe, boolean implicitThis
-    ) {
+        operandStack.replace(ClassHelper.OBJECT_TYPE, operandsToRemove);
+    }
+
+    protected void makeCall(Expression origin, ClassExpression sender, Expression receiver, Expression message, Expression arguments, MethodCallerMultiAdapter adapter, boolean safe, boolean spreadSafe, boolean implicitThis) {
         // direct method call paths
         boolean containsSpreadExpression = AsmClassGenerator.containsSpreadExpression(arguments);
 
@@ -435,18 +381,18 @@ public class InvocationWriter {
     /**
      * if Class.forName(x) is recognized, make a direct method call
      */
-    protected boolean makeClassForNameCall(Expression origin, Expression receiver, Expression message, Expression arguments) {
-        if (! (receiver instanceof ClassExpression)) return false;
+    protected boolean makeClassForNameCall(final Expression origin, final Expression receiver, final Expression message, final Expression arguments) {
+        if (!(receiver instanceof ClassExpression)) return false;
         ClassExpression ce = (ClassExpression) receiver;
         if (!ClassHelper.CLASS_Type.equals(ce.getType())) return false;
         String msg = getMethodName(message);
         if (!"forName".equals(msg)) return false;
         ArgumentListExpression ae = makeArgumentList(arguments);
-        if (ae.getExpressions().size()!=1) return false;
-        return writeDirectMethodCall(CLASS_FOR_NAME_STRING,false, receiver, ae);
+        if (ae.getExpressions().size() != 1) return false;
+        return writeDirectMethodCall(CLASS_FOR_NAME_STRING, false, receiver, ae);
     }
 
-    public static ArgumentListExpression makeArgumentList(Expression arguments) {
+    public static ArgumentListExpression makeArgumentList(final Expression arguments) {
         ArgumentListExpression ae;
         if (arguments instanceof ArgumentListExpression) {
             ae = (ArgumentListExpression) arguments;
@@ -460,14 +406,15 @@ public class InvocationWriter {
         return ae;
     }
 
-    protected String getMethodName(Expression message) {
+    protected String getMethodName(final Expression message) {
         String methodName = null;
         if (message instanceof CastExpression) {
             CastExpression msg = (CastExpression) message;
             if (msg.getType() == ClassHelper.STRING_TYPE) {
                 final Expression methodExpr = msg.getExpression();
-                if (methodExpr instanceof ConstantExpression)
-                  methodName = methodExpr.getText();
+                if (methodExpr instanceof ConstantExpression) {
+                    methodName = methodExpr.getText();
+                }
             }
         }
 
@@ -478,28 +425,6 @@ public class InvocationWriter {
         return methodName;
     }
 
-    private boolean isFunctionInterfaceCall(MethodCallExpression call) {
-        if (!"call".equals(call.getMethodAsString())) {
-            return false;
-        }
-
-        Expression objectExpression = call.getObjectExpression();
-
-        if (null == objectExpression) {
-            return false;
-        }
-
-        if (AsmClassGenerator.isThisExpression(objectExpression)) {
-            return false;
-        }
-
-        if (ClassHelper.isFunctionalInterface(objectExpression.getType())) {
-            return true;
-        }
-
-        return false;
-    }
-
     public void writeInvokeMethod(MethodCallExpression call) {
         if (isClosureCall(call)) {
             // let's invoke the closure method
@@ -508,54 +433,62 @@ public class InvocationWriter {
             if (isFunctionInterfaceCall(call)) {
                 call = transformToRealMethodCall(call);
             }
-
-            boolean isSuperMethodCall = usesSuper(call);
             MethodCallerMultiAdapter adapter = invokeMethod;
-            if (isSuperMethodCall && call.isSafe()) {
-                // safe is not necessary here because "super" is always not null
-                // but keeping the flag would trigger a VerifyError (see GROOVY-6045)
-                call.setSafe(false);
+            Expression objectExpression = call.getObjectExpression();
+            if (AsmClassGenerator.isSuperExpression(objectExpression)) {
+                adapter = invokeMethodOnSuper;
+            } else if (AsmClassGenerator.isThisExpression(objectExpression)) {
+                adapter = invokeMethodOnCurrent;
+            }
+            if (isStaticInvocation(call)) {
+                adapter = invokeStaticMethod;
+            }
+            Expression messageName = new CastExpression(ClassHelper.STRING_TYPE, call.getMethod());
+            makeCall(call, objectExpression, messageName, call.getArguments(), adapter, call.isSafe(), call.isSpreadSafe(), call.isImplicitThis());
+        }
+    }
+
+    private static boolean isFunctionInterfaceCall(final MethodCallExpression call) {
+        if ("call".equals(call.getMethodAsString())) {
+            Expression objectExpression = call.getObjectExpression();
+            if (!AsmClassGenerator.isThisExpression(objectExpression)) {
+                return ClassHelper.isFunctionalInterface(objectExpression.getType());
             }
-            if (AsmClassGenerator.isThisExpression(call.getObjectExpression())) adapter = invokeMethodOnCurrent;
-            if (isSuperMethodCall) adapter = invokeMethodOnSuper;
-            if (isStaticInvocation(call)) adapter = invokeStaticMethod;
-            makeInvokeMethodCall(call, isSuperMethodCall, adapter);
         }
+        return false;
     }
 
-    private MethodCallExpression transformToRealMethodCall(MethodCallExpression call) {
+    private static MethodCallExpression transformToRealMethodCall(MethodCallExpression call) {
         ClassNode type = call.getObjectExpression().getType();
-        final MethodNode methodNode = ClassHelper.findSAM(type);
+        MethodNode methodNode = ClassHelper.findSAM(type);
 
         call = (MethodCallExpression) call.transformExpression(expression -> {
             if (!(expression instanceof ConstantExpression)) {
                 return expression;
             }
-
             return new ConstantExpression(methodNode.getName());
         });
         call.setMethodTarget(methodNode);
         return call;
     }
 
-    private boolean isClosureCall(MethodCallExpression call) {
+    private boolean isClosureCall(final MethodCallExpression call) {
         // are we a local variable?
         // it should not be an explicitly "this" qualified method call
         // and the current class should have a possible method
-
         ClassNode classNode = controller.getClassNode();
         String methodName = call.getMethodAsString();
-        if (methodName==null) return false;
+        if (methodName == null) return false;
         if (!call.isImplicitThis()) return false;
         if (!AsmClassGenerator.isThisExpression(call.getObjectExpression())) return false;
         FieldNode field = classNode.getDeclaredField(methodName);
         if (field == null) return false;
         if (isStaticInvocation(call) && !field.isStatic()) return false;
         Expression arguments = call.getArguments();
-        return ! classNode.hasPossibleMethod(methodName, arguments);
+        return !classNode.hasPossibleMethod(methodName, arguments);
     }
 
-    private void invokeClosure(Expression arguments, String methodName) {
+    private void invokeClosure(final Expression arguments, final String methodName) {
         AsmClassGenerator acg = controller.getAcg();
         acg.visitVariableExpression(new VariableExpression(methodName));
         controller.getOperandStack().box();
@@ -568,66 +501,52 @@ public class InvocationWriter {
         controller.getOperandStack().replace(ClassHelper.OBJECT_TYPE);
     }
 
-    private boolean isStaticInvocation(MethodCallExpression call) {
+    private boolean isStaticInvocation(final MethodCallExpression call) {
         if (!AsmClassGenerator.isThisExpression(call.getObjectExpression())) return false;
         if (controller.isStaticMethod()) return true;
         return controller.isStaticContext() && !call.isImplicitThis();
     }
-    
-    private static boolean usesSuper(MethodCallExpression call) {
-        Expression expression = call.getObjectExpression();
-        if (expression instanceof VariableExpression) {
-            VariableExpression varExp = (VariableExpression) expression;
-            String variable = varExp.getName();
-            return variable.equals("super");
-        }
-        return false;
-    }
 
-    public void writeInvokeStaticMethod(StaticMethodCallExpression call) {
-        makeCall(call,
-                new ClassExpression(call.getOwnerType()),
-                new ConstantExpression(call.getMethod()),
-                call.getArguments(),
-                InvocationWriter.invokeStaticMethod,
-                false, false, false);
+    public void writeInvokeStaticMethod(final StaticMethodCallExpression call) {
+        Expression receiver = new ClassExpression(call.getOwnerType());
+        Expression messageName = new ConstantExpression(call.getMethod());
+        makeCall(call, receiver, messageName, call.getArguments(), InvocationWriter.invokeStaticMethod, false, false, false);
     }
-    
-    private boolean writeDirectConstructorCall(ConstructorCallExpression call) {
+
+    private boolean writeDirectConstructorCall(final ConstructorCallExpression call) {
         if (!controller.isFastPath()) return false;
-        
-        StatementMeta meta = call.getNodeMetaData(StatementMeta.class);
+
+        OptimizingStatementWriter.StatementMeta meta = call.getNodeMetaData(OptimizingStatementWriter.StatementMeta.class);
         ConstructorNode cn = null;
-        if (meta!=null) cn = (ConstructorNode) meta.target;
-        if (cn==null) return false;
-        
+        if (meta != null) cn = (ConstructorNode) meta.target;
+        if (cn == null) return false;
+
         String ownerDescriptor = prepareConstructorCall(cn);
         TupleExpression args = makeArgumentList(call.getArguments());
         loadArguments(args.getExpressions(), cn.getParameters());
         finnishConstructorCall(cn, ownerDescriptor, args.getExpressions().size());
-        
+
         return true;
     }
-    
-    protected String prepareConstructorCall(ConstructorNode cn) {
+
+    protected String prepareConstructorCall(final ConstructorNode cn) {
         String owner = BytecodeHelper.getClassInternalName(cn.getDeclaringClass());
         MethodVisitor mv = controller.getMethodVisitor();
-        
         mv.visitTypeInsn(NEW, owner);
         mv.visitInsn(DUP);
         return owner;
     }
-    
-    protected void finnishConstructorCall(ConstructorNode cn, String ownerDescriptor, int argsToRemove) {
+
+    protected void finnishConstructorCall(final ConstructorNode cn, final String ownerDescriptor, final int argsToRemove) {
         String desc = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, cn.getParameters());
         MethodVisitor mv = controller.getMethodVisitor();
         mv.visitMethodInsn(INVOKESPECIAL, ownerDescriptor, "<init>", desc, false);
-        
+
         controller.getOperandStack().remove(argsToRemove);
         controller.getOperandStack().push(cn.getDeclaringClass());
     }
 
-    protected void writeNormalConstructorCall(ConstructorCallExpression call) {
+    protected void writeNormalConstructorCall(final ConstructorCallExpression call) {
         Expression arguments = call.getArguments();
         if (arguments instanceof TupleExpression) {
             TupleExpression tupleExpression = (TupleExpression) arguments;
@@ -637,36 +556,33 @@ public class InvocationWriter {
             }
         }
 
-        Expression receiverClass = new ClassExpression(call.getType());
-        controller.getCallSiteWriter().makeCallSite(
-                receiverClass, CallSiteWriter.CONSTRUCTOR,
-                arguments, false, false, false,
-                false);
+        Expression receiver = new ClassExpression(call.getType());
+        controller.getCallSiteWriter().makeCallSite(receiver, CallSiteWriter.CONSTRUCTOR, arguments, false, false, false, false);
     }
-    
-    public void writeInvokeConstructor(ConstructorCallExpression call) {
+
+    public void writeInvokeConstructor(final ConstructorCallExpression call) {
         if (writeDirectConstructorCall(call)) return;
         if (writeAICCall(call)) return;
         writeNormalConstructorCall(call);
     }
 
-    protected boolean writeAICCall(ConstructorCallExpression call) {
+    protected boolean writeAICCall(final ConstructorCallExpression call) {
         if (!call.isUsingAnonymousInnerClass()) return false;
         ConstructorNode cn = call.getType().getDeclaredConstructors().get(0);
         OperandStack os = controller.getOperandStack();
-        
+
         String ownerDescriptor = prepareConstructorCall(cn);
-        
+
         List<Expression> args = makeArgumentList(call.getArguments()).getExpressions();
         Parameter[] params = cn.getParameters();
         // if a this appears as parameter here, then it should be
-        // not static, unless we are in a static method. But since 
+        // not static, unless we are in a static method. But since
         // ACG#visitVariableExpression does the opposite for this case, we
         // push here an explicit this. This should not have any negative effect
         // sine visiting a method call or property with implicit this will push
         // a new value for this again.
         controller.getCompileStack().pushImplicitThis(true);
-        for (int i=0; i<params.length; i++) {
+        for (int i = 0, n = params.length; i < n; i += 1) {
             Parameter p = params[i];
             Expression arg = args.get(i);
             if (arg instanceof VariableExpression) {
@@ -681,8 +597,8 @@ public class InvocationWriter {
         finnishConstructorCall(cn, ownerDescriptor, args.size());
         return true;
     }
-    
-    private void loadVariableWithReference(VariableExpression var) {
+
+    private void loadVariableWithReference(final VariableExpression var) {
         if (!var.isUseReferenceDirectly()) {
             var.visit(controller.getAcg());
         } else {
@@ -690,11 +606,11 @@ public class InvocationWriter {
         }
     }
 
-    public final void makeSingleArgumentCall(Expression receiver, String message, Expression arguments) {
+    public final void makeSingleArgumentCall(final Expression receiver, final String message, final Expression arguments) {
         makeSingleArgumentCall(receiver, message, arguments, false);
     }
 
-    public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments, boolean safe) {
+    public void makeSingleArgumentCall(final Expression receiver, final String message, final Expression arguments, final boolean safe) {
         controller.getCallSiteWriter().makeSingleArgumentCall(receiver, message, arguments, safe);
     }
 
@@ -704,7 +620,7 @@ public class InvocationWriter {
         controller.getCompileStack().pop();
     }
 
-    private void visitSpecialConstructorCall(ConstructorCallExpression call) {
+    private void visitSpecialConstructorCall(final ConstructorCallExpression call) {
         if (controller.getClosureWriter().addGeneratedClosureConstructorCall(call)) return;
         ClassNode callNode = controller.getClassNode();
         if (call.isSuperCall()) callNode = callNode.getSuperClass();
@@ -714,21 +630,18 @@ public class InvocationWriter {
         }
     }
 
-    private static List<ConstructorNode> sortConstructors(ConstructorCallExpression call, ClassNode callNode) {
+    private static List<ConstructorNode> sortConstructors(final ConstructorCallExpression call, final ClassNode callNode) {
         // sort in a new list to prevent side effects
-        List<ConstructorNode> constructors = new ArrayList<ConstructorNode>(callNode.getDeclaredConstructors());
-        Comparator comp = (arg0, arg1) -> {
-            ConstructorNode c0 = (ConstructorNode) arg0;
-            ConstructorNode c1 = (ConstructorNode) arg1;
+        List<ConstructorNode> constructors = new ArrayList<>(callNode.getDeclaredConstructors());
+        constructors.sort((c0, c1) -> {
             String descriptor0 = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, c0.getParameters());
             String descriptor1 = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, c1.getParameters());
             return descriptor0.compareTo(descriptor1);
-        };
-        constructors.sort(comp);
+        });
         return constructors;
     }
 
-    private boolean makeDirectConstructorCall(List<ConstructorNode> constructors, ConstructorCallExpression call, ClassNode callNode) {
+    private boolean makeDirectConstructorCall(final List<ConstructorNode> constructors, final ConstructorCallExpression call, final ClassNode callNode) {
         if (!controller.isConstructor()) return false;
 
         Expression arguments = call.getArguments();
@@ -744,13 +657,13 @@ public class InvocationWriter {
         }
 
         ConstructorNode cn = getMatchingConstructor(constructors, argumentList);
-        if (cn==null) return false;
+        if (cn == null) return false;
         MethodVisitor mv = controller.getMethodVisitor();
         OperandStack operandStack = controller.getOperandStack();
         Parameter[] params = cn.getParameters();
 
         mv.visitVarInsn(ALOAD, 0);
-        for (int i=0; i<params.length; i++) {
+        for (int i = 0, n = params.length; i < n; i += 1) {
             Expression expression = argumentList.get(i);
             expression.visit(controller.getAcg());
             if (!AsmClassGenerator.isNullConstant(expression)) {
@@ -764,7 +677,7 @@ public class InvocationWriter {
         return true;
     }
 
-    private void makeMOPBasedConstructorCall(List<ConstructorNode> constructors, ConstructorCallExpression call, ClassNode callNode) {
+    private void makeMOPBasedConstructorCall(final List<ConstructorNode> constructors, final ConstructorCallExpression call, final ClassNode callNode) {
         MethodVisitor mv = controller.getMethodVisitor();
         OperandStack operandStack = controller.getOperandStack();
         call.getArguments().visit(controller.getAcg());
@@ -786,21 +699,21 @@ public class InvocationWriter {
             mv.visitTypeInsn(NEW, BytecodeHelper.getClassInternalName(callNode));
         }
         mv.visitInsn(SWAP);
-        TreeMap<Integer,ConstructorNode> sortedConstructors = new TreeMap<Integer, ConstructorNode>();
+        TreeMap<Integer,ConstructorNode> sortedConstructors = new TreeMap<>();
         for (ConstructorNode constructor : constructors) {
             String typeDescriptor = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, constructor.getParameters());
             int hash = BytecodeHelper.hashCode(typeDescriptor);
             ConstructorNode sameHashNode = sortedConstructors.put(hash, constructor);
-            if (sameHashNode!=null) {
-                controller.getSourceUnit().addError(
-                        new SyntaxException("Unable to compile class "+controller.getClassNode().getName() + " due to hash collision in constructors", call.getLineNumber(), call.getColumnNumber()));
+            if (sameHashNode != null) {
+                controller.getSourceUnit().addError(new SyntaxException(
+                    "Unable to compile class "+controller.getClassNode().getName() + " due to hash collision in constructors", call.getLineNumber(), call.getColumnNumber()));
             }
         }
         Label[] targets = new Label[constructors.size()];
         int[] indices = new int[constructors.size()];
         Iterator<Integer> hashIt = sortedConstructors.keySet().iterator();
         Iterator<ConstructorNode> constructorIt = sortedConstructors.values().iterator();
-        for (int i = 0; i < targets.length; i++) {
+        for (int i = 0, n = targets.length; i < n; i += 1) {
             targets[i] = new Label();
             indices[i] = hashIt.next();
         }
@@ -845,9 +758,9 @@ public class InvocationWriter {
             Parameter[] parameters = cn.getParameters();
             int lengthWithoutVargs = parameters.length;
             if (parameters.length > 0 && parameters[parameters.length - 1].getType().isArray()) {
-                lengthWithoutVargs--;
+                lengthWithoutVargs -= 1;
             }
-            for (int p = 0; p < lengthWithoutVargs; p++) {
+            for (int p = 0; p < lengthWithoutVargs; p += 1) {
                 loadAndCastElement(operandStack, mv, parameters, p);
             }
             if (parameters.length > lengthWithoutVargs) {
@@ -891,7 +804,7 @@ public class InvocationWriter {
         mv.visitInsn(POP);
     }
 
-    private static void loadAndCastElement(OperandStack operandStack, MethodVisitor mv, Parameter[] parameters, int p) {
+    private static void loadAndCastElement(final OperandStack operandStack, final MethodVisitor mv, final Parameter[] parameters, final int p) {
         operandStack.push(ClassHelper.OBJECT_TYPE);
         mv.visitInsn(DUP);
         BytecodeHelper.pushConstant(mv, p);
@@ -904,7 +817,7 @@ public class InvocationWriter {
     }
 
     // we match only on the number of arguments, not anything else
-    private static ConstructorNode getMatchingConstructor(List<ConstructorNode> constructors, List<Expression> argumentList) {
+    private static ConstructorNode getMatchingConstructor(final List<ConstructorNode> constructors, final List<Expression> argumentList) {
         ConstructorNode lastMatch = null;
         for (ConstructorNode cn : constructors) {
             Parameter[] params = cn.getParameters();
@@ -921,7 +834,7 @@ public class InvocationWriter {
     }
 
     /**
-     * This converts sourceType to a non primitive by using Groovy casting.
+     * Converts sourceType to a non primitive by using Groovy casting.
      * sourceType might be a primitive
      * This might be done using SBA#castToType
      */
@@ -946,12 +859,12 @@ public class InvocationWriter {
         }
     }
 
-    public void castNonPrimitiveToBool(ClassNode last) {
+    public void castNonPrimitiveToBool(final ClassNode last) {
         MethodVisitor mv = controller.getMethodVisitor();
         BytecodeHelper.unbox(mv, ClassHelper.boolean_TYPE);
     }
 
-    public void coerce(ClassNode from, ClassNode target) {
+    public void coerce(final ClassNode from, final ClassNode target) {
         if (from.isDerivedFrom(target)) return;
         MethodVisitor mv = controller.getMethodVisitor();
         OperandStack os = controller.getOperandStack();
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
index 42f2fa4..e6abdaa 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
@@ -86,6 +86,7 @@ import static org.objectweb.asm.Opcodes.IFNULL;
 import static org.objectweb.asm.Opcodes.INVOKESTATIC;
 
 public class StaticInvocationWriter extends InvocationWriter {
+
     private static final ClassNode INVOKERHELPER_CLASSNODE = ClassHelper.make(InvokerHelper.class);
     private static final Expression INVOKERHELPER_RECEIVER = new ClassExpression(INVOKERHELPER_CLASSNODE);
     private static final MethodNode INVOKERHELPER_INVOKEMETHOD = INVOKERHELPER_CLASSNODE.getMethod(
@@ -654,14 +655,12 @@ public class StaticInvocationWriter extends InvocationWriter {
             mv.visitInsn(ACONST_NULL);
             mv.visitLabel(endof);
         } else {
-            if ((adapter == AsmClassGenerator.getGroovyObjectField
-                    || adapter == AsmClassGenerator.getField ) && origin instanceof AttributeExpression) {
-                String pname = ((PropertyExpression) origin).getPropertyAsString();
+            if (origin instanceof AttributeExpression && (adapter == AsmClassGenerator.getField || adapter == AsmClassGenerator.getGroovyObjectField)) {
                 CallSiteWriter callSiteWriter = controller.getCallSiteWriter();
-                if (pname!=null && callSiteWriter instanceof StaticTypesCallSiteWriter) {
-                    StaticTypesCallSiteWriter stcsw = (StaticTypesCallSiteWriter) callSiteWriter;
-                    TypeChooser typeChooser = controller.getTypeChooser();
-                    if (stcsw.makeGetField(receiver, typeChooser.resolveType(receiver, controller.getClassNode()), pname, safe, false)) {
+                String fieldName = ((AttributeExpression) origin).getPropertyAsString();
+                if (fieldName != null && callSiteWriter instanceof StaticTypesCallSiteWriter) {
+                    ClassNode receiverType = controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
+                    if (((StaticTypesCallSiteWriter) callSiteWriter).makeGetField(receiver, receiverType, fieldName, safe, false)) {
                         return;
                     }
                 }