use of org.apache.bcel.generic.POP2 in project jop by jop-devel.
the class SimpleInliner method analyzeInvokee.
/**
* @param cs the callstring from the invoker to the invoke to inline (if recursive). Used to check DFA results.
* @param invokee the invoked method to analyze
* @param inlineData the map to populate with the parameters and the instructions to inline.
* @return true if inlining is possible
*/
private boolean analyzeInvokee(CallString cs, MethodInfo invokee, InlineData inlineData) {
// we allow loading of parameters, loading of constants, some instruction, and a return
ValueMapAnalysis values = new ValueMapAnalysis(invokee);
values.loadParameters();
InstructionList il = invokee.getCode().getInstructionList(true, false);
InstructionHandle ih = il.getStart();
// we should at least have a return instruction, so even for empty methods we should fall through
// generate the parameter mapping
int count = 0;
while (true) {
Instruction instruction = ih.getInstruction();
if (instruction instanceof PushInstruction || instruction instanceof NOP) {
values.transfer(instruction);
ih = ih.getNext();
count++;
} else {
break;
}
}
// store the mapping
for (ValueInfo value : values.getValueTable().getStack()) {
inlineData.addParam(value);
}
inlineData.setInlineStart(count);
// if we do not need an NP check, we can also inline code which does not throw an exception in the same way
boolean needsNPCheck = helper.needsNullpointerCheck(cs, invokee, false);
boolean hasNPCheck = false;
// we allow up to 5 instructions and one return before assuming that the resulting code will be too large
for (int i = 0; i < 6; i++) {
// now lets see what we have here as non-push instructions
Instruction instruction = ih.getInstruction();
if (instruction instanceof InvokeInstruction) {
if (inlineData.getInvokeSite() != null) {
// only inline at most one invoke
return false;
}
InvokeSite is = invokee.getCode().getInvokeSite(ih);
inlineData.setInvokeSite(is);
hasNPCheck |= !is.isInvokeStatic();
} else if (instruction instanceof FieldInstruction) {
if (instruction instanceof GETFIELD) {
hasNPCheck |= values.getValueTable().top().isThisReference();
}
if (instruction instanceof PUTFIELD) {
int down = values.getValueTable().top().isContinued() ? 2 : 1;
hasNPCheck |= values.getValueTable().top(down).isThisReference();
}
} else if (instruction instanceof ArithmeticInstruction || instruction instanceof ConversionInstruction || instruction instanceof StackInstruction || instruction instanceof LDC || instruction instanceof LDC2_W || instruction instanceof ARRAYLENGTH || instruction instanceof CHECKCAST || instruction instanceof NOP) {
// nothing to do, just copy them
} else if (instruction instanceof ReturnInstruction) {
if (needsNPCheck && !hasNPCheck) {
// We were nearly finished.. but NP check test failed
this.requiresNPCheck++;
if (logger.isTraceEnabled()) {
logger.trace("Not inlining " + invokee + " because it requires a NP check.");
}
return false;
}
// else we need to add pop instructions
if (instruction instanceof RETURN) {
// we do not return anything, so we must empty the stack
while (values.getValueTable().getStackSize() > 0) {
Instruction pop;
if (values.getValueTable().top().isContinued()) {
pop = new POP2();
} else {
pop = new POP();
}
inlineData.addEpilogue(pop);
values.transfer(pop);
}
return true;
} else {
Type type = ((ReturnInstruction) instruction).getType();
// javac anyway)
return values.getValueTable().getStackSize() == type.getSize();
}
} else {
// if we encounter an instruction which we do not handle, we do not inline
unhandledInstructions++;
if (logger.isTraceEnabled()) {
logger.trace("Not inlining " + invokee + " because of unhandled instruction " + instruction.toString(invokee.getClassInfo().getConstantPoolGen().getConstantPool()));
}
return false;
}
// update the stack map since we need it to handle RETURN
values.transfer(instruction);
ih = ih.getNext();
}
// too many instructions, do not inline
return false;
}
use of org.apache.bcel.generic.POP2 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