Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2003-2007 the original author or authors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 package org.codehaus.groovy.runtime.callsite;
 
 import  org.objectweb.asm.ClassWriter;
 import  org.objectweb.asm.Label;
 import  org.objectweb.asm.MethodVisitor;
 import  org.objectweb.asm.Opcodes;
 
 
 
 public class CallSiteGenerator {
 
     private static final String GRE = BytecodeHelper.getClassInternalName(ClassHelper.make(GroovyRuntimeException.class));
     
     private CallSiteGenerator () {}
     
     private static MethodVisitor writeMethod(ClassWriter cwString nameint argumentCountfinal String superClassCachedMethod cachedMethodString receiverTypeString parameterDescriptionboolean useArray) {
         MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "call" + name"(L" + receiverType + ";" + parameterDescription + ")Ljava/lang/Object;"nullnull);
         mv.visitCode();
         
         final Label tryStart = new Label();
         mv.visitLabel(tryStart);
         
         // call for checking if method is still valid
         for (int i = 0; i < argumentCount; ++imv.visitVarInsn(Opcodes.ALOAD, i);
         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, superClass"checkCall""(Ljava/lang/Object;" + parameterDescription + ")Z");
         Label l0 = new Label();
         mv.visitJumpInsn(Opcodes.IFEQ, l0);
         
         // valid method branch
         BytecodeHelper helper = new BytecodeHelper(mv);
 
         Class callClass = cachedMethod.getDeclaringClass().getTheClass();
         boolean useInterface = callClass.isInterface();
 
         String type = BytecodeHelper.getClassInternalName(callClass.getName());
         String descriptor = BytecodeHelper.getMethodDescriptor(cachedMethod.getReturnType(), cachedMethod.getNativeParameterTypes());
         
         // prepare call
         int invokeMethodCode = Opcodes.INVOKEVIRTUAL;
         if (cachedMethod.isStatic()) {
             invokeMethodCode = Opcodes.INVOKESTATIC;
         } else {
             mv.visitVarInsn(Opcodes.ALOAD, 1);
             helper.doCast(callClass);
             if (useInterfaceinvokeMethodCode = Opcodes.INVOKEINTERFACE;
         }
         
         Method method = cachedMethod.setAccessible();
         Class<?>[] parameters = method.getParameterTypes();
         int size = parameters.length;
         for (int i = 0; i < sizei++) {
             if (useArray) {
                 // unpack argument from Object[]
                 mv.visitVarInsn(Opcodes.ALOAD, 2);
                 helper.pushConstant(i);
                 mv.visitInsn(Opcodes.AALOAD);
             } else {
                 mv.visitVarInsn(Opcodes.ALOAD, i+2);
             }
 
             // cast argument to parameter class, inclusive unboxing
             // for methods with primitive types
             Class parameterType = parameters[i];
             if (parameterType.isPrimitive()) {
                 helper.unbox(parameterType);
             } else {
                 helper.doCast(parameterType);
             }
         }        
         
         // make call
         mv.visitMethodInsn(invokeMethodCodetypecachedMethod.getName(), descriptor);
 
         // produce result
         helper.box(cachedMethod.getReturnType());
         if (cachedMethod.getReturnType() == void.class) {
            mv.visitInsn(Opcodes.ACONST_NULL);
        }
        // return
        mv.visitInsn(Opcodes.ARETURN);
        
        // fall back after method change
        mv.visitLabel(l0);
        for (int i = 0; i < argumentCount; ++imv.visitVarInsn(Opcodes.ALOAD, i);
        if (!useArray) {
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/codehaus/groovy/runtime/ArrayUtil""createArray""(" + parameterDescription + ")[Ljava/lang/Object;");
        }
        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;");
        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;");
        mv.visitInsn(Opcodes.ATHROW);        
        mv.visitTryCatchBlock(tryStarttryEndcatchStart);
        
        mv.visitMaxs(0, 0);
        mv.visitEnd();
        return mv;
    }
    
    public static void genCallWithFixedParams(ClassWriter cwString namefinal String superClassCachedMethod cachedMethodString receiverType ) {
        if (cachedMethod.getParamsCount() > 4) return;
        
        StringBuilder pdescb = new StringBuilder();
        final int pc = cachedMethod.getParamsCount();
        for (int i = 0; i != pc; ++ipdescb.append("Ljava/lang/Object;");
        
        writeMethod(cw,name,pc+2,superClass,cachedMethod,receiverType,pdescb.toString(),false);
    }
    public static void genCallXxxWithArray(ClassWriter cwfinal String namefinal String superClassCachedMethod cachedMethodString receiverType) {
        writeMethod(cw,name,3,superClass,cachedMethod,receiverType,"[Ljava/lang/Object;",true);
    }
    private static void genConstructor(ClassWriter cwfinal String superClass) {
        MethodVisitor mv;
        mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>""(Lorg/codehaus/groovy/runtime/callsite/CallSite;Lgroovy/lang/MetaClassImpl;Lgroovy/lang/MetaMethod;[Ljava/lang/Class;)V"nullnull);
        mv.visitCode();
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitVarInsn(Opcodes.ALOAD, 1);
        mv.visitVarInsn(Opcodes.ALOAD, 2);
        mv.visitVarInsn(Opcodes.ALOAD, 3);
        mv.visitVarInsn(Opcodes.ALOAD, 4);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, superClass"<init>""(Lorg/codehaus/groovy/runtime/callsite/CallSite;Lgroovy/lang/MetaClassImpl;Lgroovy/lang/MetaMethod;[Ljava/lang/Class;)V");
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    public static byte[] genPogoMetaMethodSite(CachedMethod cachedMethod, ClassWriter cwString name) {
        MethodVisitor mv;
        cw.visit(Opcodes.V1_4, Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, name.replace('.','/'), null"org/codehaus/groovy/runtime/callsite/PogoMetaMethodSite"null);
        genConstructor(cw"org/codehaus/groovy/runtime/callsite/PogoMetaMethodSite");
        genCallXxxWithArray(cw"Current""org/codehaus/groovy/runtime/callsite/PogoMetaMethodSite"cachedMethod"groovy/lang/GroovyObject");
        genCallXxxWithArray(cw"""org/codehaus/groovy/runtime/callsite/PogoMetaMethodSite"cachedMethod"java/lang/Object");
        genCallWithFixedParams(cw"Current""org/codehaus/groovy/runtime/callsite/PogoMetaMethodSite"cachedMethod"groovy/lang/GroovyObject");
        genCallWithFixedParams(cw"""org/codehaus/groovy/runtime/callsite/PogoMetaMethodSite"cachedMethod"java/lang/Object");
        cw.visitEnd();
        return cw.toByteArray();
    }
    public static byte[] genPojoMetaMethodSite(CachedMethod cachedMethod, ClassWriter cwString name) {
        MethodVisitor mv;
        cw.visit(Opcodes.V1_4, Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, name.replace('.','/'), null"org/codehaus/groovy/runtime/callsite/PojoMetaMethodSite"null);
        genConstructor(cw"org/codehaus/groovy/runtime/callsite/PojoMetaMethodSite");
        genCallXxxWithArray(cw"""org/codehaus/groovy/runtime/callsite/PojoMetaMethodSite"cachedMethod"java/lang/Object");
        genCallWithFixedParams(cw"""org/codehaus/groovy/runtime/callsite/PojoMetaMethodSite"cachedMethod"java/lang/Object");
        cw.visitEnd();
        return cw.toByteArray();
    }
    public static byte[] genStaticMetaMethodSite(CachedMethod cachedMethod, ClassWriter cwString name) {
        cw.visit(Opcodes.V1_4, Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, name.replace('.','/'), null"org/codehaus/groovy/runtime/callsite/StaticMetaMethodSite"null);
        genConstructor(cw"org/codehaus/groovy/runtime/callsite/StaticMetaMethodSite");
        genCallXxxWithArray(cw"""org/codehaus/groovy/runtime/callsite/StaticMetaMethodSite"cachedMethod"java/lang/Object");
        genCallXxxWithArray(cw"Static""org/codehaus/groovy/runtime/callsite/StaticMetaMethodSite"cachedMethod"java/lang/Class");
        genCallWithFixedParams(cw"""org/codehaus/groovy/runtime/callsite/StaticMetaMethodSite"cachedMethod"java/lang/Object");
        genCallWithFixedParams(cw"Static""org/codehaus/groovy/runtime/callsite/StaticMetaMethodSite"cachedMethod"java/lang/Class");
        cw.visitEnd();
        return cw.toByteArray();
    }
    public static Constructor compilePogoMethod(CachedMethod cachedMethod) {
        ClassWriter cw = new ClassWriter(true);
        final CachedClass declClass = cachedMethod.getDeclaringClass();
        final CallSiteClassLoader callSiteLoader = declClass.getCallSiteLoader();
        final String name = callSiteLoader.createClassName(cachedMethod.setAccessible());
        final byte[] bytes = genPogoMetaMethodSite(cachedMethodcwname);
        
        return callSiteLoader.defineClassAndGetConstructor(namebytes);
    }
    public static Constructor compilePojoMethod(CachedMethod cachedMethod) {
        ClassWriter cw = new ClassWriter(true);
        final CachedClass declClass = cachedMethod.getDeclaringClass();
        final CallSiteClassLoader callSiteLoader = declClass.getCallSiteLoader();
        final String name = callSiteLoader.createClassName(cachedMethod.setAccessible());
        final byte[] bytes = genPojoMetaMethodSite(cachedMethodcwname);
        
        return callSiteLoader.defineClassAndGetConstructor(namebytes);
    }
    public static Constructor compileStaticMethod(CachedMethod cachedMethod) {
        ClassWriter cw = new ClassWriter(true);
        final CachedClass declClass = cachedMethod.getDeclaringClass();
        final CallSiteClassLoader callSiteLoader = declClass.getCallSiteLoader();
        final String name = callSiteLoader.createClassName(cachedMethod.setAccessible());
        final byte[] bytes = genStaticMetaMethodSite(cachedMethodcwname);
        
        return callSiteLoader.defineClassAndGetConstructor(namebytes);
    }
    public static boolean isCompilable (CachedMethod method) {
        return . != null || Modifier.isPublic(method.cachedClass.getModifiers()) && method.isPublic() && publicParams(method);
    }
    private static boolean publicParams(CachedMethod method) {
        for (Class nativeParamType : method.getNativeParameterTypes()) {
            if (!Modifier.isPublic(nativeParamType.getModifiers()))
                return false;
        }
        return true;
    }
New to GrepCode? Check out our FAQ X