From commits-return-10006-archive-asf-public=cust-asf.ponee.io@groovy.apache.org Tue Nov 26 22:44:49 2019 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [207.244.88.153]) by mx-eu-01.ponee.io (Postfix) with SMTP id ABB0C18065D for ; Tue, 26 Nov 2019 23:44:48 +0100 (CET) Received: (qmail 80331 invoked by uid 500); 26 Nov 2019 22:44:48 -0000 Mailing-List: contact commits-help@groovy.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@groovy.apache.org Delivered-To: mailing list commits@groovy.apache.org Received: (qmail 80322 invoked by uid 99); 26 Nov 2019 22:44:48 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 26 Nov 2019 22:44:48 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id 825348B690; Tue, 26 Nov 2019 22:44:47 +0000 (UTC) Date: Tue, 26 Nov 2019 22:44:47 +0000 To: "commits@groovy.apache.org" Subject: [groovy] branch master updated: refactor InvocationWriter to reduce duplication around makeCall MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Message-ID: <157480828720.32356.9776875632453336998@gitbox.apache.org> From: emilles@apache.org X-Git-Host: gitbox.apache.org X-Git-Repo: groovy X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: c9adec3438cdd14021362885538d336a3ddea738 X-Git-Newrev: b56d1c17cc48f024d500688d4b2a8ca4a609f1cd X-Git-Rev: b56d1c17cc48f024d500688d4b2a8ca4a609f1cd X-Git-NotificationType: ref_changed_plus_diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated 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 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 argumentList, int pos) { + private boolean lastIsArray(final List 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 argumentList, Parameter[] para) { - if (para.length==0) return; + protected void loadArguments(final List 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 lastParams = new LinkedList(); - for (int i=para.length-1; i 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() 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, "", 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 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 sortConstructors(ConstructorCallExpression call, ClassNode callNode) { + private static List sortConstructors(final ConstructorCallExpression call, final ClassNode callNode) { // sort in a new list to prevent side effects - List constructors = new ArrayList(callNode.getDeclaredConstructors()); - Comparator comp = (arg0, arg1) -> { - ConstructorNode c0 = (ConstructorNode) arg0; - ConstructorNode c1 = (ConstructorNode) arg1; + List 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 constructors, ConstructorCallExpression call, ClassNode callNode) { + private boolean makeDirectConstructorCall(final List 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 constructors, ConstructorCallExpression call, ClassNode callNode) { + private void makeMOPBasedConstructorCall(final List 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 sortedConstructors = new TreeMap(); + TreeMap 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 hashIt = sortedConstructors.keySet().iterator(); Iterator 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 constructors, List argumentList) { + private static ConstructorNode getMatchingConstructor(final List constructors, final List 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; } }