Skip to content

Instantly share code, notes, and snippets.

@melix
Created December 30, 2011 13:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save melix/1539838 to your computer and use it in GitHub Desktop.
Save melix/1539838 to your computer and use it in GitHub Desktop.
Make use of LDC for class literals when possible
Index: groovy-git/src/main/org/codehaus/groovy/classgen/Verifier.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- groovy-git/src/main/org/codehaus/groovy/classgen/Verifier.java (date 1325233165000)
+++ groovy-git/src/main/org/codehaus/groovy/classgen/Verifier.java (revision )
@@ -210,7 +210,7 @@
node.addConstructor(constructor);
}
- private void addStaticMetaClassField(ClassNode node, final String classInternalName) {
+ private void addStaticMetaClassField(final ClassNode node, final String classInternalName) {
String _staticClassInfoFieldName = "$staticClassInfo";
while (node.getDeclaredField(_staticClassInfoFieldName) != null)
_staticClassInfoFieldName = _staticClassInfoFieldName + "$";
@@ -229,8 +229,11 @@
public void visit(MethodVisitor mv) {
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
+ if (BytecodeHelper.isClassLiteralPossible(node)) {
+ BytecodeHelper.visitClassLiteral(mv,node);
+ } else {
- mv.visitMethodInsn(INVOKESTATIC, classInternalName, "$get$$class$" + classInternalName.replaceAll("\\/", "\\$"), "()Ljava/lang/Class;");
+ mv.visitMethodInsn(INVOKESTATIC, classInternalName, "$get$$class$" + classInternalName.replaceAll("\\/", "\\$"), "()Ljava/lang/Class;");
-
+ }
Label l1 = new Label();
mv.visitJumpInsn(IF_ACMPEQ, l1);
Index: groovy-git/src/main/org/codehaus/groovy/classgen/AsmClassGenerator.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- groovy-git/src/main/org/codehaus/groovy/classgen/AsmClassGenerator.java (date 1325233165000)
+++ groovy-git/src/main/org/codehaus/groovy/classgen/AsmClassGenerator.java (revision )
@@ -1294,7 +1294,7 @@
}
protected void createSyntheticStaticFields() {
- MethodVisitor mv = controller.getMethodVisitor();
+ MethodVisitor mv;
for (String staticFieldName : referencedClasses.keySet()) {
// generate a field node
FieldNode fn = controller.getClassNode().getDeclaredField(staticFieldName);
@@ -1364,23 +1364,30 @@
public void visitClassExpression(ClassExpression expression) {
ClassNode type = expression.getType();
MethodVisitor mv = controller.getMethodVisitor();
-
- if (ClassHelper.isPrimitiveType(type)) {
- ClassNode objectType = ClassHelper.getWrapper(type);
- mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(objectType), "TYPE", "Ljava/lang/Class;");
+ if (BytecodeHelper.isClassLiteralPossible(type)) {
+ if (controller.getClassNode().isInterface()) {
+ InterfaceHelperClassNode interfaceClassLoadingClass = controller.getInterfaceClassLoadingClass();
+ if (BytecodeHelper.isClassLiteralPossible(interfaceClassLoadingClass)) {
+ BytecodeHelper.visitClassLiteral(mv, interfaceClassLoadingClass);
+ controller.getOperandStack().push(ClassHelper.CLASS_Type);
+ return;
+ }
- } else {
+ } else {
+ BytecodeHelper.visitClassLiteral(mv, type);
+ controller.getOperandStack().push(ClassHelper.CLASS_Type);
+ return;
+ }
+ }
- String staticFieldName = getStaticFieldName(type);
+ String staticFieldName = getStaticFieldName(type);
- referencedClasses.put(staticFieldName,type);
+ referencedClasses.put(staticFieldName, type);
- String internalClassName = controller.getInternalClassName();
- if (controller.getClassNode().isInterface()) {
- internalClassName = BytecodeHelper.getClassInternalName(controller.getInterfaceClassLoadingClass());
- mv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
- } else {
- mv.visitMethodInsn(INVOKESTATIC, internalClassName, "$get$" + staticFieldName, "()Ljava/lang/Class;");
- }
+ String internalClassName = controller.getInternalClassName();
+ if (controller.getClassNode().isInterface()) {
+ internalClassName = BytecodeHelper.getClassInternalName(controller.getInterfaceClassLoadingClass());
+ mv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
+ } else {
+ mv.visitMethodInsn(INVOKESTATIC, internalClassName, "$get$" + staticFieldName, "()Ljava/lang/Class;");
+ }
- }
-
controller.getOperandStack().push(ClassHelper.CLASS_Type);
}
Index: groovy-git/src/main/org/codehaus/groovy/runtime/callsite/CallSiteArray.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- groovy-git/src/main/org/codehaus/groovy/runtime/callsite/CallSiteArray.java (date 1325233165000)
+++ groovy-git/src/main/org/codehaus/groovy/runtime/callsite/CallSiteArray.java (revision )
@@ -56,6 +56,11 @@
private static CallSite createCallStaticSite(CallSite callSite, Class receiver, Object[] args) {
CallSite site;
+ try {
+ Class.forName(receiver.getName(), true, receiver.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ // force call of <cinit>
+ }
MetaClass metaClass = InvokerHelper.getMetaClass(receiver);
if (metaClass instanceof MetaClassImpl) {
site = ((MetaClassImpl)metaClass).createStaticSite(callSite, args);
Index: groovy-git/src/main/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- groovy-git/src/main/org/codehaus/groovy/classgen/asm/BytecodeHelper.java (date 1325233165000)
+++ groovy-git/src/main/org/codehaus/groovy/classgen/asm/BytecodeHelper.java (revision )
@@ -22,6 +22,8 @@
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
+import java.lang.reflect.Modifier;
+
/**
* A helper class for bytecode generation with AsmClassGenerator.
*
@@ -605,5 +607,35 @@
return true;
}
return false;
+ }
+
+ /**
+ * Returns the asm type for a class node.
+ */
+ public static void visitClassLiteral(MethodVisitor mv, ClassNode classNode) {
+ if (ClassHelper.isPrimitiveType(classNode)) {
+ mv.visitFieldInsn(
+ GETSTATIC,
+ getClassInternalName(ClassHelper.getWrapper(classNode)),
+ "TYPE",
+ "Ljava/lang/Class;");
+ } else {
+ mv.visitLdcInsn(org.objectweb.asm.Type.getType(getTypeDescription(classNode)));
+ }
+ }
+
+ /**
+ * Tells if a class node is candidate for class literal bytecode optimization. If so,
+ * bytecode may use LDC instructions instead of static constant Class fields to retrieve
+ * class literals.
+ * @param classNode the classnode for which we want to know if bytecode optimization is possible
+ * @return true if the bytecode can be optimized
+ */
+ public static boolean isClassLiteralPossible(ClassNode classNode) {
+ // the current implementation only checks for public modifier, because Groovy used to allow
+ // handles on classes even if they are package protected and not in the same package.
+ // There are situations where we could make more fine grained checks, but be careful of
+ // potential breakage of existing code.
+ return Modifier.isPublic(classNode.getModifiers());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment