}
}
private void rewrite(MethodGen method, ControlFlowGraph cfg)
throws ClassNotFoundException {
InstructionFactory insFactory = new InstructionFactory(method.getConstantPool());
Vector invokeIns = new Vector();
int count = 0;
InstructionList insList = method.getInstructionList();
InstructionHandle ins = insList.getStart();
InstructionList restorer = new InstructionList();
while (ins != null) {
InstructionHandle next = ins.getNext();
// if not traversed by the analyser, then don't rewrite
InstructionContext context = null;
Frame frame = null;
try {
context = cfg.contextOf(ins);
frame = context.getOutFrame(new ArrayList());
} catch (AssertionViolatedException ave) {
// empty
}
if (frame != null) {
if (rewriteable(method, ins)) {
// Add frame saver and restorer for the current breakpoint
// determine type of object for the method invocation
InvokeInstruction invoke = (InvokeInstruction)ins.getInstruction();
Type[] arguments = invoke.getArgumentTypes(method.getConstantPool());
ObjectType objecttype = null;
if (!(invoke instanceof INVOKESTATIC)) {
objecttype = (ObjectType)context.getInFrame().getStack().peek(arguments.length);
}
InstructionList rList = restoreFrame(method, ins, insFactory, frame, objecttype);
insList.append(ins, saveFrame(method, ins, count++, insFactory, frame));
invokeIns.addElement(rList.getStart());
restorer.append(rList);
}
// remove all new's
if (ins.getInstruction().getOpcode() == Constants.NEW) {
try {
// remove additional dup's
while (next != null && next.getInstruction().getOpcode() == Constants.DUP) {
context = cfg.contextOf(next);
frame = context.getOutFrame(new ArrayList());
InstructionHandle newnext = next.getNext();
insList.delete(next);
next = newnext;
}
InstructionTargeter[] targeter = ins.getTargeters();
if (targeter != null) {
InstructionHandle newnext = ins.getNext();
for (int i = 0; i < targeter.length; i++) {
targeter[i].updateTarget(ins, newnext);
}
}
insList.delete(ins);
} catch (TargetLostException tle) {
throw new ClassNotFoundException(tle.getMessage(), tle);
}
} else if (ins.getInstruction().getOpcode() == Constants.INVOKESPECIAL) {
// duplicate stack before invokespecial to insert uninitialized object
frame = context.getInFrame();
InvokeInstruction invoke = (InvokeInstruction)ins.getInstruction();
Type[] arguments = invoke.getArgumentTypes(method.getConstantPool());
OperandStack os = frame.getStack();
Type type = os.peek(arguments.length);
if (type instanceof UninitializedObjectType) {
ObjectType objecttype = ((UninitializedObjectType) type).getInitialized();
InstructionList duplicator = duplicateStack(method, invoke, objecttype);
InstructionTargeter[] targeter = ins.getTargeters();
if (targeter!=null) {
InstructionHandle newnext = duplicator.getStart();
for(int i=0; i < targeter.length; i++) {
targeter[i].updateTarget(ins, newnext);
}
}
insList.insert(ins, duplicator);
}
}
}
ins = next;
}
InstructionHandle firstIns = insList.getStart();
if (count > 0) {
InstructionHandle[] tableTargets = new InstructionHandle[count];
int[] match = new int[count];
for (int i = 0; i < count; i++) {
match[i] = i;
}
invokeIns.copyInto(tableTargets);
insList.insert(restorer);
// select frame restorer
insList.insert(new TABLESWITCH(match, tableTargets, firstIns));
insList.insert(insFactory.createInvoke(STACK_CLASS, getPopMethod(Type.INT), Type.INT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
insList.insert(InstructionFactory.createLoad(STACK_TYPE, method.getMaxLocals()+1));
// test if the continuation should be restored
insList.insert(new IFEQ(firstIns));
insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, RESTORING_METHOD, Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals()));
}
// get stack from current continuation and store in the last local variable
insList.insert(InstructionFactory.createStore(STACK_TYPE, method.getMaxLocals()+1));
insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, STACK_METHOD, STACK_TYPE,
Type.NO_ARGS, Constants.INVOKEVIRTUAL));
InstructionHandle restore_handle = insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals()));
// if not continuation exists, create empty stack
insList.insert(new GOTO(firstIns));
insList.insert(InstructionFactory.createStore(STACK_TYPE, method.getMaxLocals()+1));
insList.insert(insFactory.createInvoke(STACK_CLASS, Constants.CONSTRUCTOR_NAME, Type.VOID, Type.NO_ARGS, Constants. INVOKESPECIAL));
insList.insert(InstructionFactory.createDup(STACK_TYPE.getSize()));
insList.insert(insFactory.createNew(STACK_TYPE));
// test if no current continuation exists
insList.insert(new IFNONNULL(restore_handle));
insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, method.getMaxLocals()));
// get current continuation and store in the next to last local variable
insList.insert(InstructionFactory.createStore(CONTINUATION_TYPE, method.getMaxLocals()));
insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, CONTINUATION_METHOD, CONTINUATION_TYPE,
Type.NO_ARGS, Constants.INVOKESTATIC));
// make room for additional objects
method.setMaxLocals(method.getMaxLocals() + 2);
method.setMaxStack(method.getMaxStack() + 2);