use of org.apache.bcel.generic.DUP2 in project jop by jop-devel.
the class SimpleInliner method analyzeInvokeSite.
/**
* Check if the invokesite can be modified in a way so that the parameters are passed in the correct order
* @param invokeSite the invokesite to inline.
* @param invokee the invoked method.
* @param inlineData the map to store the analyzer results
* @return true if the prologue can be changed to match the expected behaviour
*/
private boolean analyzeInvokeSite(InvokeSite invokeSite, MethodInfo invokee, InlineData inlineData) {
MethodInfo invoker = invokeSite.getInvoker();
ConstantPoolGen invokerCpg = invoker.getConstantPoolGen();
InstructionHandle invoke = invokeSite.getInstructionHandle();
// Check epilogue
Type[] ret = StackHelper.produceStack(invokerCpg, invoke.getInstruction());
// works if the invoked method returns the same (single) type as the replaced instruction..
boolean match = (ret.length == 1 && TypeHelper.canAssign(invokee.getType(), ret[0]));
// return something but doesn't then it is a JVM call and throws an exception.
if (!match && !invokee.getType().equals(Type.VOID)) {
return false;
}
// Check and build prologue
Type[] args = StackHelper.consumeStack(invokerCpg, invoke.getInstruction());
List<Instruction> oldPrologue = new LinkedList<Instruction>();
int cnt = 0;
InstructionHandle current = invoke;
while (cnt < args.length) {
if (current.hasTargeters()) {
// stay within the basic block
break;
}
current = current.getPrev();
Instruction instr = current.getInstruction();
// we only rearrange push-instructions
if (!(instr instanceof PushInstruction) || (instr instanceof DUP) || (instr instanceof DUP2)) {
break;
}
// we add this instruction to the old prologue to replace
cnt++;
oldPrologue.add(0, instr);
}
inlineData.setOldPrologueLength(cnt);
List<ValueInfo> params = inlineData.getParams();
// other parameters must be used in the order they are pushed on the stack, we do not rearrange them
int offset = args.length - cnt;
for (int i = 0; i < offset; i++) {
if (i >= params.size()) {
Type t = args[i];
// unused argument, we cannot remove the push instruction so we pop it
inlineData.addPrologue(t.getSize() == 2 ? new POP2() : new POP());
} else {
ValueInfo value = params.get(i);
int argNum = value.getParamNr();
if (!invokee.isStatic()) {
argNum++;
}
if (argNum != i) {
return false;
}
}
}
// Now, we create a new prologue using the expected argument values and the old push instructions
for (int i = offset; i < params.size(); i++) {
ValueInfo value = params.get(i);
if (value.isThisReference() || value.isParamReference()) {
int argNum = value.getParamNr();
if (!invokee.isStatic()) {
argNum++;
}
if (argNum < offset) {
// loading a param a second time which we do not duplicate, cannot inline this
return false;
}
// To be on the safe side, copy the instruction in case a param is used more than once
Instruction instr = oldPrologue.get(argNum - offset).copy();
inlineData.addPrologue(instr);
} else if (value.isNullReference()) {
inlineData.addPrologue(InstructionConstants.ACONST_NULL);
} else if (value.isConstantValue() || value.isStaticFieldReference()) {
// We need to push a constant on the stack
Instruction instr = value.getConstantValue().createPushInstruction(invoker.getConstantPoolGen());
inlineData.addPrologue(instr);
} else if (!value.isContinued()) {
throw new AssertionError("Unhandled value type");
}
}
return true;
}
Aggregations