byte[] nullAdaptClass(final InputStream is, final String name) throws Exception { JavaClass jc = new ClassParser(is, name + ".class").parse(); ClassGen cg = new ClassGen(jc); String cName = cg.getClassName(); ConstantPoolGen cp = cg.getConstantPool(); Method[] ms = cg.getMethods(); for (int j = 0; j < ms.length; ++j) { MethodGen mg = new MethodGen(ms[j], cg.getClassName(), cp); boolean lv = ms[j].getLocalVariableTable() == null; boolean ln = ms[j].getLineNumberTable() == null; if (lv) { mg.removeLocalVariables(); } if (ln) { mg.removeLineNumbers(); } mg.stripAttributes(skipDebug); InstructionList il = mg.getInstructionList(); if (il != null) { InstructionHandle ih = il.getStart(); while (ih != null) { ih = ih.getNext(); } if (compute) { mg.setMaxStack(); mg.setMaxLocals(); } } cg.replaceMethod(ms[j], mg.getMethod()); } return cg.getJavaClass().getBytes(); }
/** * Adds a prefix to the original method. To make it callable only from within the framework * itself. * * @param mg the MethodGen * @param method the current method * @param methodSequence the methods sequence number * @param uuid the definition UUID * @return the modified method */ private Method addPrefixToMethod( final MethodGen mg, final Method method, final int methodSequence, final String uuid) { // change the method access flags (should always be set to protected) int accessFlags = mg.getAccessFlags(); if ((accessFlags & Constants.ACC_PROTECTED) == 0) { // set the protected flag accessFlags |= Constants.ACC_PROTECTED; } if ((accessFlags & Constants.ACC_PRIVATE) != 0) { // clear the private flag accessFlags &= ~Constants.ACC_PRIVATE; } if ((accessFlags & Constants.ACC_PUBLIC) != 0) { // clear the public flag accessFlags &= ~Constants.ACC_PUBLIC; } mg.setName(getPrefixedMethodName(method, methodSequence, mg.getClassName())); mg.setAccessFlags(accessFlags); mg.setMaxStack(); mg.setMaxLocals(); return mg.getMethod(); }
private void createMethod(Element method) throws IllegalXMLVMException { il = new InstructionList(); instructionHandlerManager = new InstructionHandlerManager(il); String methodName = method.getAttributeValue("name"); Element signature = method.getChild("signature", nsXMLVM); Type retType = collectReturnType(signature); Type[] argTypes = collectArgumentTypes(signature); short accessFlags = getAccessFlags(method); if (methodName.equals( ".cctor")) // Same concept, different names in .net/JVM. Note we are doing init of statics // for a class { System.out.println("Changed name to clinit"); methodName = "<clinit>"; accessFlags = 0x8; // static } MethodGen m = new MethodGen( accessFlags, retType, argTypes, null, methodName, fullQualifiedClassName, il, _cp); Element code = method.getChild("code", nsXMLVM); createCode(code); instructionHandlerManager.checkConsistency(); m.setMaxLocals(); m.setMaxStack(); _cg.addMethod(m.getMethod()); il.dispose(); }
Method generate(String currentClass, ConstantPoolGen cpg) { InstructionList il = new InstructionList(); int instanceOffset = 0; short flags = Constants.ACC_PUBLIC; if (invokeKind != INVOKESTATIC) { instanceOffset = 1; il.append(InstructionFactory.createThis()); } else { flags |= Constants.ACC_STATIC; } int pos = 0; for (int i = 0; i < args.length; i++) { il.append(InstructionFactory.createLoad(args[i], pos + instanceOffset)); pos += args[i].getSize(); } il.append( new InstructionFactory(cpg) .createInvoke(targetClass, methodName, returnType, args, invokeKind)); il.append(InstructionFactory.createReturn(returnType)); MethodGen newMethod = new MethodGen( flags, returnType, args, /*argNames*/ null, accessorName, currentClass, il, cpg); newMethod.setMaxLocals(); newMethod.setMaxStack(); return newMethod.getMethod(); }
private Method generateSuperAccessor( ConstantPoolGen cpg, String className, SuperMethodDescriptor superMethod, InstructionFactory factory) { int endPos = superMethod.signature.indexOf(')'); String segment = superMethod.signature.substring(1, endPos); String[] typeNames = (segment.length() > 0) ? segment.split(",") : new String[0]; Type[] argTypes = new Type[typeNames.length]; for (int i = 0; i < argTypes.length; i++) argTypes[i] = Type.getType(typeNames[i]); int index = superMethod.signature.lastIndexOf(')') + 1; Type returnType = Type.getType(superMethod.signature.substring(index)); Type baseType = new ObjectType(className); Type[] wrapperTypes = new Type[argTypes.length + 1]; System.arraycopy(argTypes, 0, wrapperTypes, 1, argTypes.length); wrapperTypes[0] = baseType; String[] argNames = new String[wrapperTypes.length]; for (int i = 0; i < argNames.length; i++) { argNames[i] = "arg" + i; } InstructionList il = new InstructionList(); MethodGen mg = new MethodGen( (Constants.ACC_PUBLIC | Constants.ACC_STATIC), returnType, wrapperTypes, argNames, OT_PREFIX + superMethod.methodName + "$super", className, il, cpg); il.append(InstructionFactory.createLoad(baseType, 0)); // first argument is base instance for (int i = 0; i < argTypes.length; i++) il.append(InstructionFactory.createLoad(argTypes[i], i + 1)); // if super method is also callin bound directly invoke the orig-version // (to avoid that BaseMethodTransformation.checkReplaceWickedSuper() has to rewrite this code // again): String methodName = (CallinBindingManager.isBoundBaseMethod( superMethod.superClass, superMethod.methodName, superMethod.signature)) ? genOrigMethName(superMethod.methodName) : superMethod.methodName; il.append( factory.createInvoke( superMethod.superClass, methodName, returnType, argTypes, INVOKESPECIAL)); il.append(InstructionFactory.createReturn(returnType)); mg.setMaxStack(); mg.setMaxLocals(); return mg.getMethod(); }
/** * Transforms the init method to create the newly added join point member field. * * @param cp the ConstantPoolGen * @param cg the ClassGen * @param init the constructor for the class * @param method the current method * @param factory the objectfactory * @param methodSequence the methods sequence number * @return the modified constructor */ private MethodGen createJoinPointField( final ConstantPoolGen cp, final ClassGen cg, final Method init, final Method method, final InstructionFactory factory, final int methodSequence) { final MethodGen mg = new MethodGen(init, cg.getClassName(), cp); final InstructionList il = mg.getInstructionList(); final InstructionHandle[] ihs = il.getInstructionHandles(); // grab the handle to the the return instruction of the constructor InstructionHandle ih = ihs[0]; for (int i = 0; i < ihs.length; i++) { Instruction instruction = ihs[i].getInstruction(); if (instruction instanceof ReturnInstruction) { ih = ihs[i]; // set the instruction handle to the return instruction break; } } final String joinPoint = getJoinPointName(method, methodSequence); final InstructionHandle ihPost; ihPost = il.insert(ih, factory.createLoad(Type.OBJECT, 0)); il.insert(ih, factory.createNew(TransformationUtil.THREAD_LOCAL_CLASS)); il.insert(ih, InstructionConstants.DUP); il.insert( ih, factory.createInvoke( TransformationUtil.THREAD_LOCAL_CLASS, "<init>", Type.VOID, new Type[] {}, Constants.INVOKESPECIAL)); il.insert( ih, factory.createFieldAccess( cg.getClassName(), joinPoint, new ObjectType(TransformationUtil.THREAD_LOCAL_CLASS), Constants.PUTFIELD)); il.redirectBranches(ih, ihPost); mg.setMaxStack(); mg.setMaxLocals(); return mg; }
private void createMethod_0() { InstructionList il = new InstructionList(); MethodGen method = new MethodGen( ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[] {}, "<init>", objectType, il, _cp); InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0)); il.append( _factory.createInvoke( "java.lang.Object", "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); InstructionHandle ih_4 = il.append(_factory.createReturn(Type.VOID)); method.setMaxStack(); method.setMaxLocals(); _cg.addMethod(method.getMethod()); il.dispose(); }
/** * Generates a setter method for the field described by 'fd' in the class 'class_name'. * * @param cpg the ConstantPoolGen of the class * @param class_name the name of the class * @param fd the FieldDescriptor describing the affected field * @param factory an InstructionFactory for this class * @return the generated getter method */ private Method generateSetter( ConstantPoolGen cpg, String class_name, FieldDescriptor fd, InstructionFactory factory) { String fieldName = fd.getFieldName(); Type fieldType = Type.getType(fd.getFieldSignature()); Type baseType = new ObjectType(class_name); Type[] argumentTypes; String[] argumentNames; if (fd.isStaticField()) { argumentTypes = new Type[] {fieldType}; argumentNames = new String[] {"new_value"}; } else { argumentTypes = new Type[] {baseType, fieldType}; argumentNames = new String[] {"base_obj", "new_value"}; } InstructionList il = new InstructionList(); MethodGen mg = new MethodGen( (Constants.ACC_PUBLIC | Constants.ACC_STATIC), Type.VOID, argumentTypes, argumentNames, OT_PREFIX + "set$" + fieldName, class_name, il, cpg); int argumentPosition; // position for the argument holding the new field value. if (!fd.isStaticField()) { il.append( InstructionFactory.createLoad( baseType, 0)); // first argument is at slot 0 in static methods argumentPosition = 1; } else { argumentPosition = 0; } il.append(InstructionFactory.createLoad(fieldType, argumentPosition)); short fieldKind = fd.isStaticField() ? Constants.PUTSTATIC : Constants.PUTFIELD; il.append(factory.createFieldAccess(class_name, fieldName, fieldType, fieldKind)); il.append(InstructionFactory.createReturn(Type.VOID)); mg.removeNOPs(); mg.setMaxStack(); mg.setMaxLocals(); return mg.getMethod(); }
/** Adds code in nl to start of method mg * */ public static void add_to_start(MethodGen mg, InstructionList nl) { // Add the code before the first instruction InstructionList il = mg.getInstructionList(); InstructionHandle old_start = il.getStart(); InstructionHandle new_start = il.insert(nl); // Move any LineNumbers and local variable that currently point to // the first instruction to include the new instructions. Other // targeters (branches, exceptions) should not include the new // code if (old_start.hasTargeters()) { for (InstructionTargeter it : old_start.getTargeters()) { if ((it instanceof LineNumberGen) || (it instanceof LocalVariableGen)) it.updateTarget(old_start, new_start); } } mg.setMaxStack(); mg.setMaxLocals(); }
/** * Generates a getter method for the field described by 'fd' in the class 'class_name'. * * @param cpg the ConstantPoolGen of the class * @param class_name the name of the class * @param fd the FieldDescriptor describing the affected field * @param factory an InstructionFactory for this class * @return the generated getter method */ private Method generateGetter( ConstantPoolGen cpg, String class_name, FieldDescriptor fd, InstructionFactory factory) { String fieldName = fd.getFieldName(); Type fieldType = Type.getType(fd.getFieldSignature()); Type baseType = new ObjectType(class_name); InstructionList il = new InstructionList(); String[] argumentNames; Type[] argumentTypes; if (fd.isStaticField()) { argumentNames = new String[0]; argumentTypes = new Type[0]; } else { argumentNames = new String[] {"base_obj"}; argumentTypes = new Type[] {baseType}; } MethodGen mg = new MethodGen( (Constants.ACC_PUBLIC | Constants.ACC_STATIC), fieldType, argumentTypes, argumentNames, OT_PREFIX + "get$" + fieldName, class_name, il, cpg); if (!fd.isStaticField()) il.append( InstructionFactory.createLoad( baseType, 0)); // first argument is at slot 0 in static methods short fieldKind = fd.isStaticField() ? Constants.GETSTATIC : Constants.GETFIELD; il.append(factory.createFieldAccess(class_name, fieldName, fieldType, fieldKind)); il.append(InstructionFactory.createReturn(fieldType)); mg.removeNOPs(); mg.setMaxStack(); mg.setMaxLocals(); return mg.getMethod(); }
public void createFixture(JavaClassGenerator classGen) { MethodGen methodGen = new MethodGen( Constants.ACC_PUBLIC | Constants.ACC_STATIC, // public and static org.apache.bcel.generic.Type.VOID, // return type new org.apache.bcel.generic.Type[] // parameters {this.getDefiningClass().toBCEL()}, null, // parameters names: we do not care "fixture" + fixtureNum, // method's name classGen.getClassName(), // defining class classGen.generateJavaBytecode(getCode()), // bytecode of the method classGen.getConstantPool()); // constant pool // we must always call these methods before the getMethod() // method below. They set the number of local variables and stack // elements used by the code of the method methodGen.setMaxStack(); methodGen.setMaxLocals(); // we add a method to the class that we are generating classGen.addMethod(methodGen.getMethod()); }
byte[] counterAdaptClass(final InputStream is, final String name) throws Exception { JavaClass jc = new ClassParser(is, name + ".class").parse(); ClassGen cg = new ClassGen(jc); String cName = cg.getClassName(); ConstantPoolGen cp = cg.getConstantPool(); if (!cg.isInterface()) { FieldGen fg = new FieldGen(ACC_PUBLIC, Type.getType("I"), "_counter", cp); cg.addField(fg.getField()); } Method[] ms = cg.getMethods(); for (int j = 0; j < ms.length; ++j) { MethodGen mg = new MethodGen(ms[j], cg.getClassName(), cp); if (!mg.getName().equals("<init>") && !mg.isStatic() && !mg.isAbstract() && !mg.isNative()) { if (mg.getInstructionList() != null) { InstructionList il = new InstructionList(); il.append(new ALOAD(0)); il.append(new ALOAD(0)); il.append(new GETFIELD(cp.addFieldref(name, "_counter", "I"))); il.append(new ICONST(1)); il.append(new IADD()); il.append(new PUTFIELD(cp.addFieldref(name, "_counter", "I"))); mg.getInstructionList().insert(il); mg.setMaxStack(Math.max(mg.getMaxStack(), 2)); boolean lv = ms[j].getLocalVariableTable() == null; boolean ln = ms[j].getLineNumberTable() == null; if (lv) { mg.removeLocalVariables(); } if (ln) { mg.removeLineNumbers(); } cg.replaceMethod(ms[j], mg.getMethod()); } } } return cg.getJavaClass().getBytes(); }
static void nullBCELAdapt(final byte[] b) throws IOException { JavaClass jc = new ClassParser(new ByteArrayInputStream(b), "class-name").parse(); ClassGen cg = new ClassGen(jc); ConstantPoolGen cp = cg.getConstantPool(); Method[] ms = cg.getMethods(); for (int k = 0; k < ms.length; ++k) { MethodGen mg = new MethodGen(ms[k], cg.getClassName(), cp); boolean lv = ms[k].getLocalVariableTable() == null; boolean ln = ms[k].getLineNumberTable() == null; if (lv) { mg.removeLocalVariables(); } if (ln) { mg.removeLineNumbers(); } mg.stripAttributes(skipDebug); InstructionList il = mg.getInstructionList(); if (il != null) { InstructionHandle ih = il.getStart(); while (ih != null) { ih = ih.getNext(); } if (compute) { mg.setMaxStack(); mg.setMaxLocals(); } if (computeFrames) { ModifiedPass3bVerifier verif; verif = new ModifiedPass3bVerifier(jc, k); verif.do_verify(); } } cg.replaceMethod(ms[k], mg.getMethod()); } cg.getJavaClass().getBytes(); }
/** * Makes the member method transformations. * * @param context the transformation context * @param klass the class set. */ public void transformCode(final Context context, final Klass klass) { // loop over all the definitions for (Iterator it = m_definitions.iterator(); it.hasNext(); ) { AspectWerkzDefinition definition = (AspectWerkzDefinition) it.next(); definition.loadAspects(context.getLoader()); final ClassGen cg = klass.getClassGen(); ClassMetaData classMetaData = BcelMetaDataMaker.createClassMetaData(context.getJavaClass(cg)); if (classFilter(definition, classMetaData, cg)) { return; } final InstructionFactory factory = new InstructionFactory(cg); final ConstantPoolGen cpg = cg.getConstantPool(); final Method[] methods = cg.getMethods(); // get the indexes for the <init> methods List initIndexes = new ArrayList(); for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals("<init>")) { initIndexes.add(new Integer(i)); } } // build and sort the method lookup list final List methodLookupList = new ArrayList(); for (int i = 0; i < methods.length; i++) { MethodMetaData methodMetaData = BcelMetaDataMaker.createMethodMetaData(methods[i]); if (methodFilter(definition, classMetaData, methodMetaData, methods[i])) { continue; } methodLookupList.add(methods[i]); } Collections.sort(methodLookupList, BCELMethodComparator.getInstance()); final Map methodSequences = new HashMap(); final List proxyMethods = new ArrayList(); boolean isClassAdvised = false; for (int i = 0; i < methods.length; i++) { MethodMetaData methodMetaData = BcelMetaDataMaker.createMethodMetaData(methods[i]); // filter the methods if (methodFilter(definition, classMetaData, methodMetaData, methods[i]) || methods[i].isStatic()) { continue; } isClassAdvised = true; final MethodGen mg = new MethodGen(methods[i], cg.getClassName(), cpg); // take care of identification of overloaded methods by inserting a sequence number if (methodSequences.containsKey(methods[i].getName())) { int sequence = ((Integer) methodSequences.get(methods[i].getName())).intValue(); methodSequences.remove(methods[i].getName()); sequence++; methodSequences.put(methods[i].getName(), new Integer(sequence)); } else { methodSequences.put(methods[i].getName(), new Integer(1)); } final int methodLookupId = methodLookupList.indexOf(methods[i]); final int methodSequence = ((Integer) methodSequences.get(methods[i].getName())).intValue(); // handleCallToOverriddenSuperClassMethod(mg, cg, cpg, factory, methodSequence, context); addJoinPointField(cpg, cg, mg, methodSequence); // get the join point controller final String controllerClassName = definition.getJoinPointController(classMetaData, methodMetaData); // advise all the constructors for (Iterator it2 = initIndexes.iterator(); it2.hasNext(); ) { final int initIndex = ((Integer) it2.next()).intValue(); methods[initIndex] = createJoinPointField(cpg, cg, methods[initIndex], methods[i], factory, methodSequence) .getMethod(); } proxyMethods.add( createProxyMethod( cpg, cg, mg, factory, methodLookupId, methodSequence, methods[i].getAccessFlags(), definition.getUuid(), controllerClassName)); methods[i] = addPrefixToMethod(mg, methods[i], methodSequence, definition.getUuid()); mg.setMaxStack(); } if (isClassAdvised) { context.markAsAdvised(); // update the old methods cg.setMethods(methods); // add the proxy methods for (Iterator it2 = proxyMethods.iterator(); it2.hasNext(); ) { cg.addMethod((Method) it2.next()); } } } }
/** * Processes each method in cg replacing any specified calls with static user calls. * * @param fullClassName must be packageName.className */ private boolean map_calls(ClassGen cg, String fullClassName, ClassLoader loader) { boolean transformed = false; try { pgen = cg.getConstantPool(); // Loop through each method in the class Method[] methods = cg.getMethods(); for (int i = 0; i < methods.length; i++) { MethodGen mg = new MethodGen(methods[i], cg.getClassName(), pgen); // Get the instruction list and skip methods with no instructions InstructionList il = mg.getInstructionList(); if (il == null) continue; if (debug) out.format("Original code: %s%n", mg.getMethod().getCode()); instrument_method(methods[i], mg); // Remove the Local variable type table attribute (if any). // Evidently, some changes we make require this to be updated, but // without BCEL support, that would be hard to do. Just delete it // for now (since it is optional, and we are unlikely to be used by // a debugger) for (Attribute a : mg.getCodeAttributes()) { if (is_local_variable_type_table(a)) { mg.removeCodeAttribute(a); } } // Update the instruction list mg.setInstructionList(il); mg.update(); // Update the max stack and Max Locals mg.setMaxLocals(); mg.setMaxStack(); mg.update(); // Update the method in the class cg.replaceMethod(methods[i], mg.getMethod()); if (debug) out.format("Modified code: %s%n", mg.getMethod().getCode()); // verify the new method // StackVer stackver = new StackVer(); // VerificationResult vr = stackver.do_stack_ver (mg); // log ("vr for method %s = %s%n", mg.getName(), vr); // if (vr.getStatus() != VerificationResult.VERIFIED_OK) { // System.out.printf ("Warning BCEL Verify failed for method %s: %s", // mg.getName(), vr); // System.out.printf ("Code: %n%s%n", mg.getMethod().getCode()); // System.exit(1); // } } cg.update(); } catch (Exception e) { out.format("Unexpected exception encountered: " + e); e.printStackTrace(); } return transformed; }
private static void addTimer(ClassGen cgen, Method method) { // set up the construction tools InstructionFactory ifact = new InstructionFactory(cgen); InstructionList ilist = new InstructionList(); ConstantPoolGen pgen = cgen.getConstantPool(); String cname = cgen.getClassName(); MethodGen wrapgen = new MethodGen(method, cname, pgen); wrapgen.setInstructionList(ilist); // rename a copy of the original method MethodGen methgen = new MethodGen(method, cname, pgen); cgen.removeMethod(method); String iname = methgen.getName() + "_timing"; methgen.setName(iname); cgen.addMethod(methgen.getMethod()); Type result = methgen.getReturnType(); // compute the size of the calling parameters Type[] parameters = methgen.getArgumentTypes(); int stackIndex = methgen.isStatic() ? 0 : 1; for (int i = 0; i < parameters.length; i++) { stackIndex += parameters[i].getSize(); } // save time prior to invocation ilist.append( ifact.createInvoke( "java.lang.System", "currentTimeMillis", Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC)); ilist.append(InstructionFactory.createStore(Type.LONG, stackIndex)); // call the wrapped method int offset = 0; short invoke = Constants.INVOKESTATIC; if (!methgen.isStatic()) { ilist.append(InstructionFactory.createLoad(Type.OBJECT, 0)); offset = 1; invoke = Constants.INVOKEVIRTUAL; } for (int i = 0; i < parameters.length; i++) { Type type = parameters[i]; ilist.append(InstructionFactory.createLoad(type, offset)); offset += type.getSize(); } ilist.append(ifact.createInvoke(cname, iname, result, parameters, invoke)); // store result for return later if (result != Type.VOID) { ilist.append(InstructionFactory.createStore(result, stackIndex + 2)); } // print time required for method call ilist.append( ifact.createFieldAccess( "java.lang.System", "out", new ObjectType("java.io.PrintStream"), Constants.GETSTATIC)); ilist.append(InstructionConstants.DUP); ilist.append(InstructionConstants.DUP); String text = "Call to method " + methgen.getName() + " took "; ilist.append(new PUSH(pgen, text)); ilist.append( ifact.createInvoke( "java.io.PrintStream", "print", Type.VOID, new Type[] {Type.STRING}, Constants.INVOKEVIRTUAL)); ilist.append( ifact.createInvoke( "java.lang.System", "currentTimeMillis", Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC)); ilist.append(InstructionFactory.createLoad(Type.LONG, stackIndex)); ilist.append(InstructionConstants.LSUB); ilist.append( ifact.createInvoke( "java.io.PrintStream", "print", Type.VOID, new Type[] {Type.LONG}, Constants.INVOKEVIRTUAL)); ilist.append(new PUSH(pgen, " ms.")); ilist.append( ifact.createInvoke( "java.io.PrintStream", "println", Type.VOID, new Type[] {Type.STRING}, Constants.INVOKEVIRTUAL)); // return result from wrapped method call if (result != Type.VOID) { ilist.append(InstructionFactory.createLoad(result, stackIndex + 2)); } ilist.append(InstructionFactory.createReturn(result)); // finalize the constructed method wrapgen.stripAttributes(true); wrapgen.setMaxStack(); wrapgen.setMaxLocals(); cgen.addMethod(wrapgen.getMethod()); ilist.dispose(); }
/** * Creates a proxy method for the original method specified. This method has the same signature as * the original method and catches the invocation for further processing by the framework before * redirecting to the original method. * * @todo pass the 'class' as a Class instance not a String to the join point. Add the class field * to the class using BCEL (see AdviseStaticMethodTransformer.java) * @param cp the ConstantPoolGen * @param cg the ClassGen * @param originalMethod the current method * @param factory the objectfactory * @param methodId the id of the current method in the lookup tabl * @param methodSequence the methods sequence number * @param accessFlags the access flags of the original method * @param uuid the uuid for the weave model defining the pointcut * @param controllerClassName the class name of the controller class to use * @return the proxy method */ private Method createProxyMethod( final ConstantPoolGen cp, final ClassGen cg, final MethodGen originalMethod, final InstructionFactory factory, final int methodId, final int methodSequence, final int accessFlags, final String uuid, final String controllerClassName) { InstructionList il = new InstructionList(); String joinPoint = getJoinPointName(originalMethod.getMethod(), methodSequence); final MethodGen method = new MethodGen( accessFlags, Type.getReturnType(originalMethod.getSignature()), Type.getArgumentTypes(originalMethod.getSignature()), originalMethod.getArgumentNames(), originalMethod.getName(), cg.getClassName(), il, cp); String[] exceptions = originalMethod.getExceptions(); for (int i = 0; i < exceptions.length; i++) { method.addException(exceptions[i]); } int indexParam = 1; int indexStack = 0; int indexJoinPoint = Type.getArgumentTypes(originalMethod.getSignature()).length * 2 + 1; // if (threadLocal == null) { // threadLocal = new SerializableThreadLocal(); // } il.append(factory.createLoad(Type.OBJECT, 0)); il.append( factory.createFieldAccess( cg.getClassName(), joinPoint, new ObjectType(TransformationUtil.THREAD_LOCAL_CLASS), Constants.GETFIELD)); BranchInstruction ifNotNull = factory.createBranchInstruction(Constants.IFNONNULL, null); il.append(ifNotNull); il.append(factory.createLoad(Type.OBJECT, 0)); il.append(factory.createNew(TransformationUtil.THREAD_LOCAL_CLASS)); il.append(InstructionConstants.DUP); il.append( factory.createInvoke( TransformationUtil.THREAD_LOCAL_CLASS, "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); il.append( factory.createFieldAccess( cg.getClassName(), joinPoint.toString(), new ObjectType(TransformationUtil.THREAD_LOCAL_CLASS), Constants.PUTFIELD)); // Object joinPoint = ___jp.get(); BranchInstruction biIfNotNull = null; InstructionHandle ihIfNotNull = null; ifNotNull.setTarget(il.append(factory.createLoad(Type.OBJECT, 0))); il.append( factory.createFieldAccess( cg.getClassName(), joinPoint.toString(), new ObjectType(TransformationUtil.THREAD_LOCAL_CLASS), Constants.GETFIELD)); il.append( factory.createInvoke( TransformationUtil.THREAD_LOCAL_CLASS, "get", Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); il.append(factory.createStore(Type.OBJECT, indexJoinPoint)); il.append(factory.createLoad(Type.OBJECT, indexJoinPoint)); // if (joinPoint == null) { biIfNotNull = factory.createBranchInstruction(Constants.IFNONNULL, null); il.append(biIfNotNull); // joinPoint = new WeakReference(new MemberMethodJoinPoint(uuid, this, "foo.bar.Baz", 10)); // il.append(factory.createNew(TransformationUtil.WEAK_REFERENCE_CLASS)); // il.append(InstructionConstants.DUP); il.append(factory.createNew(TransformationUtil.MEMBER_METHOD_JOIN_POINT_CLASS)); il.append(InstructionConstants.DUP); il.append(new PUSH(cp, uuid)); il.append(factory.createLoad(Type.OBJECT, 0)); il.append(new PUSH(cp, cg.getClassName())); il.append(new PUSH(cp, methodId)); il.append(new PUSH(cp, controllerClassName)); il.append( factory.createInvoke( TransformationUtil.MEMBER_METHOD_JOIN_POINT_CLASS, "<init>", Type.VOID, new Type[] {Type.STRING, Type.OBJECT, Type.STRING, Type.INT, Type.STRING}, Constants.INVOKESPECIAL)); il.append(factory.createStore(Type.OBJECT, indexJoinPoint)); // threadLocal.set(joinPoint); il.append(factory.createLoad(Type.OBJECT, 0)); il.append( factory.createFieldAccess( cg.getClassName(), joinPoint.toString(), new ObjectType(TransformationUtil.THREAD_LOCAL_CLASS), Constants.GETFIELD)); il.append(factory.createLoad(Type.OBJECT, indexJoinPoint)); il.append( factory.createInvoke( TransformationUtil.THREAD_LOCAL_CLASS, "set", Type.VOID, new Type[] {Type.OBJECT}, Constants.INVOKEVIRTUAL)); ihIfNotNull = il.append(factory.createLoad(Type.OBJECT, indexJoinPoint)); indexJoinPoint += 2; il.append(factory.createCheckCast(TransformationUtil.MEMBER_METHOD_JOIN_POINT_TYPE)); il.append(factory.createStore(Type.OBJECT, indexJoinPoint)); biIfNotNull.setTarget(ihIfNotNull); // if we have parameters, wrap them up if (Type.getArgumentTypes(originalMethod.getSignature()).length != 0) { // create and allocate the parameters array il.append(new PUSH(cp, Type.getArgumentTypes(originalMethod.getSignature()).length)); il.append(factory.createNewArray(Type.OBJECT, (short) 1)); il.append(InstructionConstants.DUP); il.append(new PUSH(cp, indexStack)); indexStack++; // add all the parameters, wrap the primitive types in their object counterparts for (int count = 0; count < Type.getArgumentTypes(originalMethod.getSignature()).length; count++) { String wrapperClass = null; BasicType type = null; boolean hasLongOrDouble = false; if (Type.getArgumentTypes(originalMethod.getSignature())[count] instanceof ObjectType || Type.getArgumentTypes(originalMethod.getSignature())[count] instanceof ArrayType) { // we have an object or an array il.append(factory.createLoad(Type.OBJECT, indexParam)); il.append(InstructionConstants.AASTORE); indexParam++; } else if (Type.getArgumentTypes(originalMethod.getSignature())[count] instanceof ArrayType) { // we have an array il.append(factory.createLoad(Type.OBJECT, indexParam)); il.append(InstructionConstants.AASTORE); indexParam++; } else if (Type.getArgumentTypes(originalMethod.getSignature())[count] instanceof BasicType) { hasLongOrDouble = false; // we have a primitive type if ((Type.getArgumentTypes(originalMethod.getSignature())[count]).equals(Type.LONG)) { wrapperClass = "java.lang.Long"; type = Type.LONG; hasLongOrDouble = true; } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count]) .equals(Type.INT)) { wrapperClass = "java.lang.Integer"; type = Type.INT; } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count]) .equals(Type.SHORT)) { wrapperClass = "java.lang.Short"; type = Type.SHORT; } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count]) .equals(Type.DOUBLE)) { wrapperClass = "java.lang.Double"; type = Type.DOUBLE; hasLongOrDouble = true; } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count]) .equals(Type.FLOAT)) { wrapperClass = "java.lang.Float"; type = Type.FLOAT; } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count]) .equals(Type.CHAR)) { wrapperClass = "java.lang.Character"; type = Type.CHAR; } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count]) .equals(Type.BYTE)) { wrapperClass = "java.lang.Byte"; type = Type.BYTE; } else if ((Type.getArgumentTypes(originalMethod.getSignature())[count]) .equals(Type.BOOLEAN)) { wrapperClass = "java.lang.Boolean"; type = Type.BOOLEAN; } else { throw new RuntimeException( "unknown parameter type: " + Type.getArgumentTypes(originalMethod.getSignature())[count]); } il.append(factory.createNew(wrapperClass)); il.append(InstructionConstants.DUP); il.append(factory.createLoad(type, indexParam)); il.append( factory.createInvoke( wrapperClass, "<init>", Type.VOID, new Type[] {type}, Constants.INVOKESPECIAL)); il.append(InstructionConstants.AASTORE); indexParam++; } // end handle basic or object type if (count != Type.getArgumentTypes(originalMethod.getSignature()).length - 1) { // if we don't have the last parameter, create the parameter on the stack il.append(InstructionConstants.DUP); il.append(new PUSH(cp, indexStack)); indexStack++; // long or double needs two registers to fit if (hasLongOrDouble) indexParam++; } } // create the object array il.append(factory.createStore(Type.OBJECT, indexParam)); // if threadsafe grab the newly retrieved local join point field from the stack il.append(factory.createLoad(Type.OBJECT, indexJoinPoint)); // invoke joinPoint.setParameter(..) il.append(factory.createLoad(Type.OBJECT, indexParam)); il.append( factory.createInvoke( TransformationUtil.MEMBER_METHOD_JOIN_POINT_CLASS, "setParameters", Type.VOID, new Type[] {new ArrayType(Type.OBJECT, 1)}, Constants.INVOKEVIRTUAL)); indexParam++; } // end - if parameters.length != 0 // if threadsafe grab the newly retrieved local join point field from the stack il.append(factory.createLoad(Type.OBJECT, indexJoinPoint)); il.append( factory.createInvoke( TransformationUtil.MEMBER_METHOD_JOIN_POINT_CLASS, "proceed", Type.OBJECT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); if (!Type.getReturnType(originalMethod.getSignature()).equals(Type.VOID)) { // create the result from the invocation il.append(factory.createStore(Type.OBJECT, indexParam)); il.append(factory.createLoad(Type.OBJECT, indexParam)); // cast the result and return it, if the return type is a // primitive type, retrieve it from the wrapped object first // unless the return object is null (AW-100) if (Type.getReturnType(originalMethod.getSignature()) instanceof BasicType) { if (Type.getReturnType(originalMethod.getSignature()).equals(Type.VOID)) {; // skip } else { BranchInstruction ifNullBranch = factory.createBranchInstruction(Constants.IFNONNULL, null); InstructionHandle elseBranch = null; il.append(ifNullBranch); if (Type.getReturnType(originalMethod.getSignature()).equals(Type.LONG)) { il.append(new PUSH(cp, 0L)); il.append(factory.createReturn(Type.LONG)); elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam)); il.append(factory.createCheckCast(new ObjectType("java.lang.Long"))); il.append( factory.createInvoke( "java.lang.Long", "longValue", Type.LONG, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.INT)) { il.append(new PUSH(cp, 0)); il.append(factory.createReturn(Type.INT)); elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam)); il.append(factory.createCheckCast(new ObjectType("java.lang.Integer"))); il.append( factory.createInvoke( "java.lang.Integer", "intValue", Type.INT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.SHORT)) { il.append(new PUSH(cp, (short) 0)); il.append(factory.createReturn(Type.SHORT)); elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam)); il.append(factory.createCheckCast(new ObjectType("java.lang.Short"))); il.append( factory.createInvoke( "java.lang.Short", "shortValue", Type.SHORT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.DOUBLE)) { il.append(new PUSH(cp, 0.0d)); il.append(factory.createReturn(Type.DOUBLE)); elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam)); il.append(factory.createCheckCast(new ObjectType("java.lang.Double"))); il.append( factory.createInvoke( "java.lang.Double", "doubleValue", Type.DOUBLE, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.FLOAT)) { il.append(new PUSH(cp, 0.0f)); il.append(factory.createReturn(Type.FLOAT)); elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam)); il.append(factory.createCheckCast(new ObjectType("java.lang.Float"))); il.append( factory.createInvoke( "java.lang.Float", "floatValue", Type.FLOAT, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.CHAR)) { il.append(new PUSH(cp, '\u0000')); il.append(factory.createReturn(Type.CHAR)); elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam)); il.append(factory.createCheckCast(new ObjectType("java.lang.Character"))); il.append( factory.createInvoke( "java.lang.Character", "charValue", Type.CHAR, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.BYTE)) { il.append(new PUSH(cp, (byte) 0)); il.append(factory.createReturn(Type.BYTE)); elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam)); il.append(factory.createCheckCast(new ObjectType("java.lang.Byte"))); il.append( factory.createInvoke( "java.lang.Byte", "byteValue", Type.BYTE, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); } else if (Type.getReturnType(originalMethod.getSignature()).equals(Type.BOOLEAN)) { il.append(new PUSH(cp, false)); il.append(factory.createReturn(Type.BOOLEAN)); elseBranch = il.append(factory.createLoad(Type.OBJECT, indexParam)); il.append(factory.createCheckCast(new ObjectType("java.lang.Boolean"))); il.append( factory.createInvoke( "java.lang.Boolean", "booleanValue", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); } else { throw new Error( "unknown return type: " + Type.getReturnType(originalMethod.getSignature())); } ifNullBranch.setTarget(elseBranch); } } else { // cast the result to the right type il.append( factory.createCast(Type.OBJECT, Type.getReturnType(originalMethod.getSignature()))); } } il.append(factory.createReturn(Type.getReturnType(originalMethod.getSignature()))); method.setMaxStack(); method.setMaxLocals(); return method.getMethod(); }