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);
}