Search in sources :

Example 1 with PushInstruction

use of org.apache.bcel.generic.PushInstruction in project candle-decompiler by bradsdavis.

the class SplitInstructionEnhancer method visitPopInstruction.

@Override
public void visitPopInstruction(PopInstruction obj) {
    // check instruction in map.
    List<InstructionHandle> ivs = this.igc.getPredecessors(this.current);
    if (ivs.size() > 1) {
        // check to see if the predecessors pushed.
        int count = 0;
        for (InstructionHandle iv : ivs) {
            InstructionHandle jvmiv = (InstructionHandle) iv;
            jvmiv = findSource(jvmiv);
            if (jvmiv.getInstruction() instanceof PushInstruction) {
                count++;
            }
        }
        if (count > 1) {
            LOG.debug("Split vertex.");
            splitVertex(this.current);
        }
    }
}
Also used : PushInstruction(org.apache.bcel.generic.PushInstruction) InstructionHandle(org.apache.bcel.generic.InstructionHandle)

Example 2 with PushInstruction

use of org.apache.bcel.generic.PushInstruction 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;
}
Also used : ArithmeticInstruction(org.apache.bcel.generic.ArithmeticInstruction) ValueMapAnalysis(com.jopdesign.jcopter.analysis.ValueMapAnalysis) ARRAYLENGTH(org.apache.bcel.generic.ARRAYLENGTH) POP2(org.apache.bcel.generic.POP2) InstructionList(org.apache.bcel.generic.InstructionList) CHECKCAST(org.apache.bcel.generic.CHECKCAST) StackInstruction(org.apache.bcel.generic.StackInstruction) ConversionInstruction(org.apache.bcel.generic.ConversionInstruction) LDC(org.apache.bcel.generic.LDC) InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) StackInstruction(org.apache.bcel.generic.StackInstruction) Instruction(org.apache.bcel.generic.Instruction) FieldInstruction(org.apache.bcel.generic.FieldInstruction) ArithmeticInstruction(org.apache.bcel.generic.ArithmeticInstruction) ConversionInstruction(org.apache.bcel.generic.ConversionInstruction) ReturnInstruction(org.apache.bcel.generic.ReturnInstruction) PushInstruction(org.apache.bcel.generic.PushInstruction) InstructionHandle(org.apache.bcel.generic.InstructionHandle) ReturnInstruction(org.apache.bcel.generic.ReturnInstruction) RETURN(org.apache.bcel.generic.RETURN) LDC2_W(org.apache.bcel.generic.LDC2_W) ValueInfo(com.jopdesign.common.type.ValueInfo) PUTFIELD(org.apache.bcel.generic.PUTFIELD) PushInstruction(org.apache.bcel.generic.PushInstruction) NOP(org.apache.bcel.generic.NOP) POP(org.apache.bcel.generic.POP) InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) GETFIELD(org.apache.bcel.generic.GETFIELD) Type(org.apache.bcel.generic.Type) InvokeSite(com.jopdesign.common.code.InvokeSite) FieldInstruction(org.apache.bcel.generic.FieldInstruction)

Example 3 with PushInstruction

use of org.apache.bcel.generic.PushInstruction 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;
}
Also used : POP2(org.apache.bcel.generic.POP2) InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) StackInstruction(org.apache.bcel.generic.StackInstruction) Instruction(org.apache.bcel.generic.Instruction) FieldInstruction(org.apache.bcel.generic.FieldInstruction) ArithmeticInstruction(org.apache.bcel.generic.ArithmeticInstruction) ConversionInstruction(org.apache.bcel.generic.ConversionInstruction) ReturnInstruction(org.apache.bcel.generic.ReturnInstruction) PushInstruction(org.apache.bcel.generic.PushInstruction) PushInstruction(org.apache.bcel.generic.PushInstruction) InstructionHandle(org.apache.bcel.generic.InstructionHandle) LinkedList(java.util.LinkedList) POP(org.apache.bcel.generic.POP) ConstantPoolGen(org.apache.bcel.generic.ConstantPoolGen) Type(org.apache.bcel.generic.Type) DUP2(org.apache.bcel.generic.DUP2) ValueInfo(com.jopdesign.common.type.ValueInfo) MethodInfo(com.jopdesign.common.MethodInfo) DUP(org.apache.bcel.generic.DUP)

Aggregations

InstructionHandle (org.apache.bcel.generic.InstructionHandle)3 PushInstruction (org.apache.bcel.generic.PushInstruction)3 ValueInfo (com.jopdesign.common.type.ValueInfo)2 ArithmeticInstruction (org.apache.bcel.generic.ArithmeticInstruction)2 ConversionInstruction (org.apache.bcel.generic.ConversionInstruction)2 FieldInstruction (org.apache.bcel.generic.FieldInstruction)2 Instruction (org.apache.bcel.generic.Instruction)2 InvokeInstruction (org.apache.bcel.generic.InvokeInstruction)2 POP (org.apache.bcel.generic.POP)2 POP2 (org.apache.bcel.generic.POP2)2 ReturnInstruction (org.apache.bcel.generic.ReturnInstruction)2 StackInstruction (org.apache.bcel.generic.StackInstruction)2 Type (org.apache.bcel.generic.Type)2 MethodInfo (com.jopdesign.common.MethodInfo)1 InvokeSite (com.jopdesign.common.code.InvokeSite)1 ValueMapAnalysis (com.jopdesign.jcopter.analysis.ValueMapAnalysis)1 LinkedList (java.util.LinkedList)1 ARRAYLENGTH (org.apache.bcel.generic.ARRAYLENGTH)1 CHECKCAST (org.apache.bcel.generic.CHECKCAST)1 ConstantPoolGen (org.apache.bcel.generic.ConstantPoolGen)1