You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2019/11/09 07:18:32 UTC

[groovy] 01/12: GROOVY-8721, GROOVY-9015: Avoid calling ClassNode#getTypeClass()

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

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

commit b307c5f8b3dac4988ca14ace7752349f47d8700b
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Nov 5 14:09:31 2019 -0600

    GROOVY-8721, GROOVY-9015: Avoid calling ClassNode#getTypeClass()
    
    GROOVY-4146
    
    (cherry picked from commit 8c66dec035ffc3fb40a1322e6e1b902e217f3d1d)
---
 .../classgen/InnerClassCompletionVisitor.java      |   4 +-
 .../groovy/classgen/asm/BytecodeHelper.java        | 153 ++++++++++-----------
 .../groovy/runtime/callsite/CallSiteGenerator.java |  44 +++---
 3 files changed, 98 insertions(+), 103 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
index 1e52435..4b8a1a2 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
@@ -168,12 +168,12 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper impleme
             mv.visitFieldInsn(GETFIELD, classInternalName, "this$0", outerClassDescriptor);
         }
     }
-    
+
     private void addDefaultMethods(InnerClassNode node) {
         final boolean isStatic = isStatic(node);
 
         ClassNode outerClass = node.getOuterClass();
-        final String classInternalName = org.codehaus.groovy.classgen.asm.BytecodeHelper.getClassInternalName(node);
+        final String classInternalName = BytecodeHelper.getClassInternalName(node);
         final String outerClassInternalName = getInternalName(outerClass, isStatic);
         final String outerClassDescriptor = getTypeDescriptor(outerClass, isStatic);
         final int objectDistance = getObjectDistance(outerClass);
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
index 7491ca8..58323b5 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
@@ -24,7 +24,6 @@ import org.codehaus.groovy.ast.CompileUnit;
 import org.codehaus.groovy.ast.GenericsType;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.decompiled.DecompiledClassNode;
 import org.codehaus.groovy.classgen.asm.util.TypeUtil;
 import org.codehaus.groovy.reflection.ReflectionCache;
 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
@@ -48,17 +47,22 @@ import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
  * A helper class for bytecode generation with AsmClassGenerator.
  */
 public class BytecodeHelper implements Opcodes {
-    
-    private static String DTT_CLASSNAME = BytecodeHelper.getClassInternalName(DefaultTypeTransformation.class.getName());
 
+    private static String DTT_CLASSNAME = BytecodeHelper.getClassInternalName(DefaultTypeTransformation.class);
+
+    /**
+     * @return the ASM internal name of the type
+     */
     public static String getClassInternalName(ClassNode t) {
-        if (t.isPrimaryClassNode() || t instanceof DecompiledClassNode) {
-            if (t.isArray()) return "[L"+getClassInternalName(t.getComponentType())+";";
-            return getClassInternalName(t.getName());
+        if (t.isArray()) {
+            return TypeUtil.getDescriptionByType(t);
         }
-        return getClassInternalName(t.getTypeClass());
+        return getClassInternalName(t.getName());
     }
 
+    /**
+     * @return the ASM internal name of the type
+     */
     public static String getClassInternalName(Class t) {
         return org.objectweb.asm.Type.getInternalName(t);
     }
@@ -70,55 +74,56 @@ public class BytecodeHelper implements Opcodes {
         return name.replace('.', '/');
     }
 
+    /**
+     * Returns a method descriptor for the given {@link org.codehaus.groovy.ast.MethodNode}.
+     *
+     * @param methodNode the method node for which to create the descriptor
+     * @return a method descriptor as defined in section JVMS section 4.3.3
+     */
+    public static String getMethodDescriptor(MethodNode methodNode) {
+        return getMethodDescriptor(methodNode.getReturnType(), methodNode.getParameters());
+    }
+
+    /**
+     * @return the ASM method type descriptor
+     */
     public static String getMethodDescriptor(ClassNode returnType, Parameter[] parameters) {
         ClassNode[] parameterTypes = new ClassNode[parameters.length];
-        for (int i = 0; i < parameters.length; i++) {
+        for (int i = 0, n = parameters.length; i < n; i += 1) {
             parameterTypes[i] = parameters[i].getType();
         }
-
         return getMethodDescriptor(returnType, parameterTypes);
     }
 
+    /**
+     * @return the ASM method type descriptor
+     */
     public static String getMethodDescriptor(ClassNode returnType, ClassNode[] parameterTypes) {
         StringBuilder buffer = new StringBuilder(100);
-        buffer.append("(");
+        buffer.append('(');
         for (ClassNode parameterType : parameterTypes) {
             buffer.append(getTypeDescription(parameterType));
         }
-        buffer.append(")");
+        buffer.append(')');
         buffer.append(getTypeDescription(returnType));
         return buffer.toString();
     }
 
     /**
-     * Returns a method descriptor for the given {@link org.codehaus.groovy.ast.MethodNode}.
-     *
-     * @param methodNode the method node for which to create the descriptor
-     * @return a method descriptor as defined in section JVMS section 4.3.3
-     */
-    public static String getMethodDescriptor(MethodNode methodNode) {
-        return getMethodDescriptor(methodNode.getReturnType(), methodNode.getParameters());
-    }
-    
-    /**
      * @return the ASM method type descriptor
      */
     public static String getMethodDescriptor(Class returnType, Class[] paramTypes) {
         // lets avoid class loading
         StringBuilder buffer = new StringBuilder(100);
-        buffer.append("(");
+        buffer.append('(');
         for (Class paramType : paramTypes) {
             buffer.append(getTypeDescription(paramType));
         }
-        buffer.append(")");
+        buffer.append(')');
         buffer.append(getTypeDescription(returnType));
         return buffer.toString();
     }
 
-    public static String getTypeDescription(Class c) {
-        return org.objectweb.asm.Type.getDescriptor(c);
-    }
-
     /**
      * array types are special:
      * eg.: String[]: classname: [Ljava.lang.String;
@@ -132,16 +137,18 @@ public class BytecodeHelper implements Opcodes {
      */
     public static String getClassLoadingTypeDescription(ClassNode c) {
         String desc = TypeUtil.getDescriptionByType(c);
-
         if (!c.isArray()) {
             if (desc.startsWith("L") && desc.endsWith(";")) {
                 desc = desc.substring(1, desc.length() - 1); // remove "L" and ";"
             }
         }
-
         return desc.replace('/', '.');
     }
 
+    public static String getTypeDescription(Class c) {
+        return org.objectweb.asm.Type.getDescriptor(c);
+    }
+
     /**
      * array types are special:
      * eg.: String[]: classname: [Ljava/lang/String;
@@ -165,24 +172,20 @@ public class BytecodeHelper implements Opcodes {
         if (ClassHelper.isPrimitiveType(d.redirect())) {
             d = d.redirect();
         }
-
         String desc = TypeUtil.getDescriptionByType(d);
-
         if (!end && desc.endsWith(";")) {
             desc = desc.substring(0, desc.length() - 1);
         }
-
         return desc;
     }
 
-
     /**
      * @return an array of ASM internal names of the type
      */
     public static String[] getClassInternalNames(ClassNode[] names) {
         int size = names.length;
         String[] answer = new String[size];
-        for (int i = 0; i < size; i++) {
+        for (int i = 0; i < size; i += 1) {
             answer[i] = getClassInternalName(names[i]);
         }
         return answer;
@@ -218,7 +221,7 @@ public class BytecodeHelper implements Opcodes {
                 }
         }
     }
-    
+
     /**
      * Negate a boolean on stack.
      */
@@ -235,16 +238,6 @@ public class BytecodeHelper implements Opcodes {
     }
 
     /**
-     * load a message on the stack and remove it right away. Good for put a mark in the generated bytecode for debugging purpose.
-     *
-     * @param msg
-     */
-    /*public void mark(String msg) {
-        mv.visitLdcInsn(msg);
-        mv.visitInsn(POP);
-    }*/
-
-    /**
      * returns a name that Class.forName() can take. Notably for arrays:
      * [I, [Ljava.lang.String; etc
      * Regular object type:  java.lang.String
@@ -281,10 +274,6 @@ public class BytecodeHelper implements Opcodes {
         return name.replace('/', '.');
     }
 
-    /*public void dup() {
-        mv.visitInsn(DUP);
-    }*/
-
     private static boolean hasGenerics(Parameter[] param) {
         if (param.length == 0) return false;
         for (Parameter parameter : param) {
@@ -333,7 +322,6 @@ public class BytecodeHelper implements Opcodes {
                 if (anInterface.isUsingGenerics()) return true;
             }
         }
-
         return false;
     }
 
@@ -374,7 +362,6 @@ public class BytecodeHelper implements Opcodes {
             GenericsType gt = new GenericsType(type);
             writeGenericsBounds(ret, gt, false);
         }
-
         return ret.toString();
     }
 
@@ -443,8 +430,8 @@ public class BytecodeHelper implements Opcodes {
         } else {
             mv.visitTypeInsn(
                     CHECKCAST,
-                    type.isArray() ? 
-                            BytecodeHelper.getTypeDescription(type) : 
+                    type.isArray() ?
+                            BytecodeHelper.getTypeDescription(type) :
                             BytecodeHelper.getClassInternalName(type.getName()));
         }
     }
@@ -480,50 +467,62 @@ public class BytecodeHelper implements Opcodes {
         } else {
             mv.visitTypeInsn(
                     CHECKCAST,
-                    type.isArray() ? 
-                            BytecodeHelper.getTypeDescription(type) : 
+                    type.isArray() ?
+                            BytecodeHelper.getTypeDescription(type) :
                                 BytecodeHelper.getClassInternalName(type.getName()));
         }
     }
 
     /**
-     * Generates the bytecode to unbox the current value on the stack
-     */
-    public static void unbox(MethodVisitor mv, Class type) {
-        if (type.isPrimitive() && type != Void.TYPE) {
-            String returnString = "(Ljava/lang/Object;)" + BytecodeHelper.getTypeDescription(type);
-            mv.visitMethodInsn(INVOKESTATIC, DTT_CLASSNAME, type.getName() + "Unbox", returnString, false);
-        }
-    }
-
-    public static void unbox(MethodVisitor mv, ClassNode type) {
-        if (type.isPrimaryClassNode()) return;
-        unbox(mv, type.getTypeClass());
-    }
-
-    /**
-     * box top level operand
+     * Generates the bytecode to autobox the current value on the stack.
      */
     @Deprecated
     public static boolean box(MethodVisitor mv, ClassNode type) {
-        if (type.isPrimaryClassNode()) return false;
-        return box(mv, type.getTypeClass());
+        if (ClassHelper.isPrimitiveType(type) && !"void".equalsIgnoreCase(type.getName())) {
+            box(mv, BytecodeHelper.getTypeDescription(type));
+            return true;
+        }
+        return false;
     }
 
-    
     /**
-     * Generates the bytecode to autobox the current value on the stack
+     * Generates the bytecode to autobox the current value on the stack.
      */
     @Deprecated
     public static boolean box(MethodVisitor mv, Class type) {
         if (ReflectionCache.getCachedClass(type).isPrimitive && type != void.class) {
-            String returnString = "(" + BytecodeHelper.getTypeDescription(type) + ")Ljava/lang/Object;";
-            mv.visitMethodInsn(INVOKESTATIC, DTT_CLASSNAME, "box", returnString, false);
+            box(mv, BytecodeHelper.getTypeDescription(type));
             return true;
         }
         return false;
     }
 
+    private static void box(MethodVisitor mv, String typeDescription) {
+        mv.visitMethodInsn(INVOKESTATIC, DTT_CLASSNAME, "box", "(" + typeDescription + ")Ljava/lang/Object;", false);
+    }
+
+    /**
+     * Generates the bytecode to unbox the current value on the stack.
+     */
+    public static void unbox(MethodVisitor mv, ClassNode type) {
+        if (ClassHelper.isPrimitiveType(type) && !"void".equalsIgnoreCase(type.getName())) {
+            unbox(mv, type.getName(), BytecodeHelper.getTypeDescription(type));
+        }
+    }
+
+    /**
+     * Generates the bytecode to unbox the current value on the stack.
+     */
+    public static void unbox(MethodVisitor mv, Class type) {
+        if (type.isPrimitive() && type != Void.TYPE) {
+            unbox(mv, type.getName(), BytecodeHelper.getTypeDescription(type));
+        }
+    }
+
+    private static void unbox(MethodVisitor mv, String typeName, String typeDescription) {
+        mv.visitMethodInsn(INVOKESTATIC, DTT_CLASSNAME, typeName + "Unbox", "(Ljava/lang/Object;)" + typeDescription, false);
+    }
+
     /**
      * Visits a class literal. If the type of the classnode is a primitive type,
      * the generated bytecode will be a GETSTATIC Integer.TYPE.
diff --git a/src/main/java/org/codehaus/groovy/runtime/callsite/CallSiteGenerator.java b/src/main/java/org/codehaus/groovy/runtime/callsite/CallSiteGenerator.java
index 1267cfe..b9cbbf7 100644
--- a/src/main/java/org/codehaus/groovy/runtime/callsite/CallSiteGenerator.java
+++ b/src/main/java/org/codehaus/groovy/runtime/callsite/CallSiteGenerator.java
@@ -18,8 +18,6 @@
  */
 package org.codehaus.groovy.runtime.callsite;
 
-import groovy.lang.GroovyRuntimeException;
-import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
 import org.codehaus.groovy.reflection.CachedClass;
@@ -36,23 +34,22 @@ import java.lang.reflect.Modifier;
 
 public class CallSiteGenerator {
 
-    private static final String GRE = BytecodeHelper.getClassInternalName(ClassHelper.make(GroovyRuntimeException.class));
-    
-    private CallSiteGenerator () {}
-    
+    private CallSiteGenerator() {
+    }
+
     private static MethodVisitor writeMethod(ClassWriter cw, String name, int argumentCount, final String superClass, CachedMethod cachedMethod, String receiverType, String parameterDescription, boolean useArray) {
         MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "call" + name, "(L" + receiverType + ";" + parameterDescription + ")Ljava/lang/Object;", null, null);
         mv.visitCode();
-        
+
         final Label tryStart = new Label();
         mv.visitLabel(tryStart);
-        
+
         // call for checking if method is still valid
         for (int i = 0; i < argumentCount; ++i) mv.visitVarInsn(Opcodes.ALOAD, i);
         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, superClass, "checkCall", "(Ljava/lang/Object;" + parameterDescription + ")Z", false);
         Label l0 = new Label();
         mv.visitJumpInsn(Opcodes.IFEQ, l0);
-        
+
         // valid method branch
 
         Class callClass = cachedMethod.getDeclaringClass().getTheClass();
@@ -60,7 +57,7 @@ public class CallSiteGenerator {
 
         String type = BytecodeHelper.getClassInternalName(callClass.getName());
         String descriptor = BytecodeHelper.getMethodDescriptor(cachedMethod.getReturnType(), cachedMethod.getNativeParameterTypes());
-        
+
         // prepare call
         int invokeMethodCode = Opcodes.INVOKEVIRTUAL;
         if (cachedMethod.isStatic()) {
@@ -86,8 +83,8 @@ public class CallSiteGenerator {
             // cast argument to parameter class, inclusive unboxing
             // for methods with primitive types
             BytecodeHelper.doCast(mv, parameters[i]);
-        }        
-        
+        }
+
         // make call
         mv.visitMethodInsn(invokeMethodCode, type, cachedMethod.getName(), descriptor, useInterface);
 
@@ -99,7 +96,7 @@ public class CallSiteGenerator {
 
         // return
         mv.visitInsn(Opcodes.ARETURN);
-        
+
         // fall back after method change
         mv.visitLabel(l0);
         for (int i = 0; i < argumentCount; ++i) mv.visitVarInsn(Opcodes.ALOAD, i);
@@ -108,29 +105,28 @@ public class CallSiteGenerator {
         }
         mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/codehaus/groovy/runtime/callsite/CallSiteArray", "defaultCall" + name, "(Lorg/codehaus/groovy/runtime/callsite/CallSite;L" + receiverType + ";[Ljava/lang/Object;)Ljava/lang/Object;", false);
         mv.visitInsn(Opcodes.ARETURN);
-        
+
         // exception unwrapping for stackless exceptions
         final Label tryEnd = new Label();
         mv.visitLabel(tryEnd);
         final Label catchStart = new Label();
         mv.visitLabel(catchStart);
         mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/codehaus/groovy/runtime/ScriptBytecodeAdapter", "unwrap", "(Lgroovy/lang/GroovyRuntimeException;)Ljava/lang/Throwable;", false);
-        mv.visitInsn(Opcodes.ATHROW);        
-        mv.visitTryCatchBlock(tryStart, tryEnd, catchStart, GRE);
-        
+        mv.visitInsn(Opcodes.ATHROW);
+        mv.visitTryCatchBlock(tryStart, tryEnd, catchStart, "groovy/lang/GroovyRuntimeException");
+
         mv.visitMaxs(0, 0);
         mv.visitEnd();
         return mv;
     }
-    
 
     public static void genCallWithFixedParams(ClassWriter cw, String name, final String superClass, CachedMethod cachedMethod, String receiverType ) {
         if (cachedMethod.getParamsCount() > 4) return;
-        
+
         StringBuilder pdescb = new StringBuilder();
         final int pc = cachedMethod.getParamsCount();
         for (int i = 0; i != pc; ++i) pdescb.append("Ljava/lang/Object;");
-        
+
         writeMethod(cw,name,pc+2,superClass,cachedMethod,receiverType,pdescb.toString(),false);
     }
 
@@ -203,7 +199,7 @@ public class CallSiteGenerator {
         String internalName = name.replace('.', '/');
         classHeader(cw, internalName, "org/codehaus/groovy/runtime/callsite/StaticMetaMethodSite");
         cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "__constructor__", "Ljava/lang/reflect/Constructor;", null, null);
- 
+
         genConstructor(cw, "org/codehaus/groovy/runtime/callsite/StaticMetaMethodSite", internalName);
 
         genCallXxxWithArray(cw, "", "org/codehaus/groovy/runtime/callsite/StaticMetaMethodSite", cachedMethod, "java/lang/Object");
@@ -232,7 +228,7 @@ public class CallSiteGenerator {
         final String name = callSiteLoader.createClassName(cachedMethod.getName());
 
         final byte[] bytes = genPogoMetaMethodSite(cachedMethod, cw, name);
-        
+
         return callSiteLoader.defineClassAndGetConstructor(name, bytes);
     }
 
@@ -244,7 +240,7 @@ public class CallSiteGenerator {
         final String name = callSiteLoader.createClassName(cachedMethod.getName());
 
         final byte[] bytes = genPojoMetaMethodSite(cachedMethod, cw, name);
-        
+
         return callSiteLoader.defineClassAndGetConstructor(name, bytes);
     }
 
@@ -256,7 +252,7 @@ public class CallSiteGenerator {
         final String name = callSiteLoader.createClassName(cachedMethod.getName());
 
         final byte[] bytes = genStaticMetaMethodSite(cachedMethod, cw, name);
-        
+
         return callSiteLoader.defineClassAndGetConstructor(name, bytes);
     }