/** * 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; }
/** Compiles a method that overloads NodeSortRecord.extractValueFromDOM() */ private static MethodGenerator compileExtract( Vector sortObjects, NodeSortRecordGenerator sortRecord, ConstantPoolGen cpg, String className) { final InstructionList il = new InstructionList(); // String NodeSortRecord.extractValueFromDOM(dom,node,level); final CompareGenerator extractMethod = new CompareGenerator( ACC_PUBLIC | ACC_FINAL, org.apache.bcel.generic.Type.STRING, new org.apache.bcel.generic.Type[] { Util.getJCRefType(DOM_INTF_SIG), org.apache.bcel.generic.Type.INT, org.apache.bcel.generic.Type.INT, Util.getJCRefType(TRANSLET_SIG), org.apache.bcel.generic.Type.INT }, new String[] {"dom", "current", "level", "translet", "last"}, "extractValueFromDOM", className, il, cpg); // Values needed for the switch statement final int levels = sortObjects.size(); final int match[] = new int[levels]; final InstructionHandle target[] = new InstructionHandle[levels]; InstructionHandle tblswitch = null; // Compile switch statement only if the key has multiple levels if (levels > 1) { // Put the parameter to the swtich statement on the stack il.append(new ILOAD(extractMethod.getLocalIndex("level"))); // Append the switch statement here later on tblswitch = il.append(new NOP()); } // Append all the cases for the switch statment for (int level = 0; level < levels; level++) { match[level] = level; final Sort sort = (Sort) sortObjects.elementAt(level); target[level] = il.append(NOP); sort.translateSelect(sortRecord, extractMethod); il.append(ARETURN); } // Compile def. target for switch statement if key has multiple levels if (levels > 1) { // Append the default target - it will _NEVER_ be reached InstructionHandle defaultTarget = il.append(new PUSH(cpg, EMPTYSTRING)); il.insert(tblswitch, new TABLESWITCH(match, target, defaultTarget)); il.append(ARETURN); } return extractMethod; }
/** * Replace instruction ih in list il with the instructions in new_il. If new_il is null, do * nothing */ protected static void replace_instructions( InstructionList il, InstructionHandle ih, InstructionList new_il) { if ((new_il == null) || new_il.isEmpty()) return; // If there is only one new instruction, just replace it in the handle if (new_il.getLength() == 1) { ih.setInstruction(new_il.getEnd().getInstruction()); return; } // Get the start and end instruction of the new instructions InstructionHandle new_end = new_il.getEnd(); InstructionHandle new_start = il.insert(ih, new_il); // Move all of the branches from the old instruction to the new start il.redirectBranches(ih, new_start); // Move other targets to the new instuctions. if (ih.hasTargeters()) { for (InstructionTargeter it : ih.getTargeters()) { if (it instanceof LineNumberGen) { it.updateTarget(ih, new_start); } else if (it instanceof LocalVariableGen) { it.updateTarget(ih, new_end); } else if (it instanceof CodeExceptionGen) { CodeExceptionGen exc = (CodeExceptionGen) it; if (exc.getStartPC() == ih) exc.updateTarget(ih, new_start); else if (exc.getEndPC() == ih) exc.updateTarget(ih, new_end); else if (exc.getHandlerPC() == ih) exc.setHandlerPC(new_start); else System.out.printf("Malformed CodeException: %s%n", exc); } else { System.out.printf("unexpected target %s%n", it); } } } // Remove the old handle. There should be no targeters left to it. try { il.delete(ih); } catch (Exception e) { throw new Error("Can't delete instruction", e); } }
/** 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(); }