/** * 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; }
/** * 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(); }
/** * 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(); }
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(); }
public Instruction createInstructionGetstatic(Element inst) throws IllegalXMLVMException { String classType = inst.getAttributeValue("class-type"); String field = inst.getAttributeValue("field"); Type type = parseTypeString(inst.getAttributeValue("type")); return _factory.createFieldAccess(classType, field, type, Constants.GETSTATIC); }
/** * 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(); }