Java Code Examples for proguard.classfile.instruction.Instruction#length()

The following examples show how to use proguard.classfile.instruction.Instruction#length() . These examples are extracted from open source projects. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)
{
    if (instructionVisitor != CodeAttributeEditor.this)
    {
        throw new UnsupportedOperationException("Unexpected visitor ["+instructionVisitor+"]");
    }

    for (int index = 0; index < instructions.length; index++)
    {
        Instruction instruction = instructions[index];

        instruction.accept(clazz, method, codeAttribute, offset, CodeAttributeEditor.this);

        offset += instruction.length(offset);
    }
}
 
Example 2
/**
 * Applies the given instruction visitor to all instructions in the
 * specified range of offsets.
 */
public void instructionsAccept(Clazz clazz, Method method, int startOffset, int endOffset, InstructionVisitor instructionVisitor)
{
    int offset = startOffset;

    while (offset < endOffset)
    {
        // Note that the instruction is only volatile.
        Instruction instruction = InstructionFactory.create(code, offset);
        int instructionLength = instruction.length(offset);
        instruction.accept(clazz, method, this, offset, instructionVisitor);
        offset += instructionLength;
    }
}
 
Example 3
/**
     * Appends the given instruction with the given old offset.
     * @param oldInstructionOffset the old offset of the instruction, to which
     *                             branches and other references in the current
     *                             code fragment are pointing.
     * @param instruction          the instruction to be appended.
     */
    public void appendInstruction(int         oldInstructionOffset,
                                  Instruction instruction)
    {
        if (DEBUG)
        {
            println("["+codeLength+"] <- ", instruction.toString(oldInstructionOffset));
        }

        // Make sure the code array is large enough.
        int newCodeLength = codeLength + instruction.length(codeLength);

        ensureCodeLength(newCodeLength);

        // Remember the old offset of the appended instruction.
        oldInstructionOffsets[codeLength] = oldInstructionOffset;

        // Write the instruction.
//        instruction.accept(null,
//                           null,
//                           new CodeAttribute(0, 0, 0, 0, code, 0, null, 0, null),
//                           codeLength,
//                           instructionWriter);
        instruction.write(code, codeLength);

        // Fill out the new offset of the appended instruction.
        instructionOffsetMap[level][oldInstructionOffset] = codeLength;

        // Continue appending at the next instruction offset.
        codeLength = newCodeLength;
    }
 
Example 4
/**
 * Checks if it is possible to modifies the given code without having to
 * update any offsets.
 * @param codeAttribute the code to be changed.
 * @return the new code length.
 */
private boolean canPerformSimpleReplacements(CodeAttribute codeAttribute)
{
    if (!simple)
    {
        return false;
    }

    byte[] code       = codeAttribute.code;
    int    codeLength = codeAttribute.u4codeLength;

    // Go over all replacement instructions.
    for (int offset = 0; offset < codeLength; offset++)
    {
        // Check if the replacement instruction, if any, has a different
        // length than the original instruction.
        Instruction replacementInstruction = replacements[offset];
        if (replacementInstruction != null &&
            replacementInstruction.length(offset) !=
                InstructionFactory.create(code, offset).length(offset))
        {
            return false;
        }
    }

    return true;
}
 
Example 5
/**
 * Fills out the instruction offset map for the given code block.
 * @param oldCode   the instructions to be moved.
 * @param oldLength the code length.
 * @return the new code length.
 */
private int mapInstructions(byte[] oldCode, int oldLength)
{
    // Start mapping instructions at the beginning.
    newOffset       = 0;
    lengthIncreased = false;

    int oldOffset = 0;
    do
    {
        // Get the next instruction.
        Instruction instruction = InstructionFactory.create(oldCode, oldOffset);

        // Compute the mapping of the instruction.
        mapInstruction(oldOffset, instruction);

        oldOffset += instruction.length(oldOffset);

        if (newOffset > oldOffset)
        {
            lengthIncreased = true;
        }
    }
    while (oldOffset < oldLength);

    // Also add an entry for the first offset after the code.
    instructionOffsetMap[oldOffset] = newOffset;

    return newOffset;
}
 
Example 6
/**
 * Fills out the instruction offset map for the given instruction.
 * @param oldOffset   the instruction's old offset.
 * @param instruction the instruction to be moved.
 */
private void mapInstruction(int         oldOffset,
                            Instruction instruction)
{
    instructionOffsetMap[oldOffset] = newOffset;

    // Account for the pre-inserted instruction, if any.
    Instruction preInstruction = preInsertions[oldOffset];
    if (preInstruction != null)
    {
        newOffset += preInstruction.length(newOffset);
    }

    // Account for the replacement instruction, or for the current
    // instruction, if it shouldn't be  deleted.
    Instruction replacementInstruction = replacements[oldOffset];
    if (replacementInstruction != null)
    {
        newOffset += replacementInstruction.length(newOffset);
    }
    else if (!deleted[oldOffset])
    {
        // Note that the instruction's length may change at its new offset,
        // e.g. if it is a switch instruction.
        newOffset += instruction.length(newOffset);
    }

    // Account for the post-inserted instruction, if any.
    Instruction postInstruction = postInsertions[oldOffset];
    if (postInstruction != null)
    {
        newOffset += postInstruction.length(newOffset);
    }
}
 
Example 7
/**
 * Moves the given code block to the new offsets.
 * @param clazz         the class file of the code to be changed.
 * @param method        the method of the code to be changed.
 * @param codeAttribute the code to be changed.
 * @param oldCode       the original code to be moved.
 * @param oldLength     the original code length.
 */
private void moveInstructions(Clazz         clazz,
                              Method        method,
                              CodeAttribute codeAttribute,
                              byte[]        oldCode,
                              int           oldLength)
{
    // Start writing instructions at the beginning.
    newOffset = 0;

    int oldOffset = 0;
    do
    {
        // Get the next instruction.
        Instruction instruction = InstructionFactory.create(oldCode, oldOffset);

        // Move the instruction to its new offset.
        moveInstruction(clazz,
                        method,
                        codeAttribute,
                        oldOffset,
                        instruction);

        oldOffset += instruction.length(oldOffset);
    }
    while (oldOffset < oldLength);
}
 
Example 8
public void write(byte[] code, int offset)
{
    for (int index = 0; index < instructions.length; index++)
    {
        Instruction instruction = instructions[index];

        instruction.write(code, offset);

        offset += instruction.length(offset);
    }
}
 
Example 9
/**
 * Returns whether the given code has any side effects.
 */
private boolean hasSideEffects(Clazz         clazz,
                               Method        method,
                               CodeAttribute codeAttribute)
{
    byte[] code   = codeAttribute.code;
    int    length = codeAttribute.u4codeLength;

    // Go over all instructions.
    int offset = 0;
    do
    {
        // Get the current instruction.
        Instruction instruction = InstructionFactory.create(code, offset);

        // Check if it may be throwing exceptions.
        if (sideEffectInstructionChecker.hasSideEffects(clazz,
                                                        method,
                                                        codeAttribute,
                                                        offset,
                                                        instruction))
        {
            return true;
        }

        // Go to the next instruction.
        offset += instruction.length(offset);
    }
    while (offset < length);

    return false;
}
 
Example 10
/**
 * Deletes the given branch instruction, or replaces it by a simpler branch
 * instruction, if possible.
 */
private void replaceBranchInstruction(Clazz       clazz,
                                      int         offset,
                                      Instruction instruction)
{
    InstructionOffsetValue branchTargets = partialEvaluator.branchTargets(offset);

    // Is there exactly one branch target (not from a goto or jsr)?
    if (branchTargets != null &&
        branchTargets.instructionOffsetCount() == 1)
    {
        // Is it branching to the next instruction?
        int branchOffset = branchTargets.instructionOffset(0) - offset;
        if (branchOffset == instruction.length(offset))
        {
            if (DEBUG) System.out.println("  Ignoring zero branch instruction at ["+offset+"]");
        }
        else
        {
            // Replace the branch instruction by a simple branch instruction.
            Instruction replacementInstruction =
                new BranchInstruction(InstructionConstants.OP_GOTO_W,
                                      branchOffset).shrink();

            replaceInstruction(clazz, offset, instruction, replacementInstruction);
        }
    }
}
 
Example 11
/**
 * Marks the code starting at the given offset.
 */
private void markCode(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset)
{
    boolean oldNext = next;

    byte[] code = codeAttribute.code;

    // Continue with the current instruction as long as we haven't marked it
    // yet.
    while (!isReachable[offset])
    {
        // Get the current instruction.
        Instruction instruction = InstructionFactory.create(code, offset);

        // Mark it as reachable.
        isReachable[offset] = true;

        // By default, we'll assume we can continue with the next
        // instruction in a moment.
        next = true;

        // Mark the branch targets, if any.
        instruction.accept(clazz, method, codeAttribute, offset, this);

        // Can we really continue with the next instruction?
        if (!next)
        {
            break;
        }

        // Go to the next instruction.
        offset += instruction.length(offset);
    }

    next = oldNext;
}
 
Example 12
/**
 * Returns whether the specified block of code may throw exceptions.
 */
private boolean mayThrowExceptions(Clazz         clazz,
                                   Method        method,
                                   CodeAttribute codeAttribute,
                                   int           startOffset,
                                   int           endOffset)
{
    byte[] code = codeAttribute.code;

    // Go over all instructions.
    int offset = startOffset;
    while (offset < endOffset)
    {
        // Get the current instruction.
        Instruction instruction = InstructionFactory.create(code, offset);

        // Check if it may be throwing exceptions.
        if (exceptionInstructionChecker.mayThrowExceptions(clazz,
                                                           method,
                                                           codeAttribute,
                                                           offset,
                                                           instruction))
        {
            return true;
        }

        // Go to the next instruction.
        offset += instruction.length(offset);
    }

    return false;
}
 
Example 13
public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute)
{
    branchTargetFinder.visitCodeAttribute(clazz, method, codeAttribute);

    // Don't bother if there aren't any subroutines anyway.
    if (!containsSubroutines(codeAttribute))
    {
        return;
    }

    if (DEBUG)
    {
        System.out.println("SubroutineInliner: processing ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]");
    }

    // Append the body of the code.
    codeAttributeComposer.reset();
    codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength);

    // Copy the non-subroutine instructions.
    int offset  = 0;
    while (offset < codeAttribute.u4codeLength)
    {
        Instruction instruction = InstructionFactory.create(codeAttribute.code, offset);
        int instructionLength = instruction.length(offset);

        // Is this returning subroutine?
        if (branchTargetFinder.isSubroutine(offset) &&
            branchTargetFinder.isSubroutineReturning(offset))
        {
            // Skip the subroutine.
            if (DEBUG)
            {
                System.out.println("  Skipping original subroutine instruction "+instruction.toString(offset));
            }

            // Append a label at this offset instead.
            codeAttributeComposer.appendLabel(offset);
        }
        else
        {
            // Copy the instruction, inlining any subroutine call recursively.
            instruction.accept(clazz, method, codeAttribute, offset, this);
        }

        offset += instructionLength;
    }

    // Copy the exceptions. Note that exceptions with empty try blocks
    // are automatically removed.
    codeAttribute.exceptionsAccept(clazz,
                                   method,
                                   subroutineExceptionInliner);

    if (DEBUG)
    {
        System.out.println("  Appending label after code at ["+offset+"]");
    }

    // Append a label just after the code.
    codeAttributeComposer.appendLabel(codeAttribute.u4codeLength);

    // End and update the code attribute.
    codeAttributeComposer.endCodeFragment();
    codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute);
}
 
Example 14
public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
{
    int startPC   = Math.max(exceptionInfo.u2startPC, clipStart);
    int endPC     = Math.min(exceptionInfo.u2endPC,   clipEnd);
    int handlerPC = exceptionInfo.u2handlerPC;
    int catchType = exceptionInfo.u2catchType;

    // Exclude any subroutine invocations that jump out of the try block,
    // by adding a try block before (and later on, after) each invocation.
    for (int offset = startPC; offset < endPC; offset++)
    {
        if (branchTargetFinder.isSubroutineInvocation(offset))
        {
            Instruction instruction = InstructionFactory.create(codeAttribute.code, offset);
            int instructionLength = instruction.length(offset);

            // Is it a subroutine invocation?
            if (!exceptionInfo.isApplicable(offset + ((BranchInstruction)instruction).branchOffset))
            {
                if (DEBUG)
                {
                    System.out.println("  Appending extra exception ["+startPC+" -> "+offset+"] -> "+handlerPC);
                }

                // Append a try block that ends before the subroutine invocation.
                codeAttributeComposer.appendException(new ExceptionInfo(startPC,
                                                                        offset,
                                                                        handlerPC,
                                                                        catchType));

                // The next try block will start after the subroutine invocation.
                startPC = offset + instructionLength;
            }
        }
    }

    if (DEBUG)
    {
        if (startPC == exceptionInfo.u2startPC &&
            endPC   == exceptionInfo.u2endPC)
        {
            System.out.println("  Appending exception ["+startPC+" -> "+endPC+"] -> "+handlerPC);
        }
        else
        {
            System.out.println("  Appending clipped exception ["+exceptionInfo.u2startPC+" -> "+exceptionInfo.u2endPC+"] ~> ["+startPC+" -> "+endPC+"] -> "+handlerPC);
        }
    }

    // Append the exception. Note that exceptions with empty try blocks
    // are automatically ignored.
    codeAttributeComposer.appendException(new ExceptionInfo(startPC,
                                                            endPC,
                                                            handlerPC,
                                                            catchType));
}
 
Example 15
/**
     * Wraps up the current code fragment, continuing with the previous one on
     * the stack.
     */
    public void endCodeFragment()
    {
        if (level < 0)
        {
            throw new IllegalArgumentException("Code fragment not begun ["+level+"]");
        }

        // Remap the instructions of the code fragment.
        int instructionOffset = codeFragmentOffsets[level];
        while (instructionOffset < codeLength)
        {
            // Get the next instruction.
            Instruction instruction = InstructionFactory.create(code, instructionOffset);

            // Does this instruction still have to be remapped?
            if (oldInstructionOffsets[instructionOffset] >= 0)
            {
                // Adapt the instruction for its new offset.
                instruction.accept(null, null, null, instructionOffset, this);

                // Write the instruction back.
//                instruction.accept(null,
//                                   null,
//                                   new CodeAttribute(0, 0, 0, 0, code, 0, null, 0, null),
//                                   instructionOffset,
//                                   instructionWriter);
                instruction.write(code, instructionOffset);

                // Don't remap this instruction again.
                oldInstructionOffsets[instructionOffset] = -1;
            }

            // Continue remapping at the next instruction offset.
            instructionOffset += instruction.length(instructionOffset);
        }

        // Correct the estimated maximum code length, now that we know the
        // actual length of this code fragment.
        maximumCodeLength += codeLength - codeFragmentOffsets[level] -
                             codeFragmentLengths[level];

        // Try to remap the exception handlers that couldn't be remapped before.
        if (allowExternalExceptionHandlers)
        {
            for (int index = 0; index < exceptionTableLength; index++)
            {
                ExceptionInfo exceptionInfo = exceptionTable[index];

                // Unmapped exception handlers are still negated.
                int handlerPC = -exceptionInfo.u2handlerPC;
                if (handlerPC > 0)
                {
                    if (remappableInstructionOffset(handlerPC))
                    {
                        exceptionInfo.u2handlerPC = remapInstructionOffset(handlerPC);
                    }
                    else if (level == 0)
                    {
                        throw new IllegalStateException("Couldn't remap exception handler offset ["+handlerPC+"]");
                    }
                }
            }
        }

        level--;
    }
 
Example 16
public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
    {
//        DEBUG = DEBUG_RESULTS =
//            clazz.getName().equals("abc/Def") &&
//            method.getName(clazz).equals("abc");

        // TODO: Remove this when the partial evaluator has stabilized.
        // Catch any unexpected exceptions from the actual visiting method.
        try
        {
            // Process the code.
            visitCodeAttribute0(clazz, method, codeAttribute);
        }
        catch (RuntimeException ex)
        {
            System.err.println("Unexpected error while performing partial evaluation:");
            System.err.println("  Class       = ["+clazz.getName()+"]");
            System.err.println("  Method      = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]");
            System.err.println("  Exception   = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");

            if (DEBUG)
            {
                method.accept(clazz, new ClassPrinter());

                System.out.println("Evaluation results:");

                int offset = 0;
                do
                {
                    if (isBranchOrExceptionTarget(offset))
                    {
                        System.out.println("Branch target from ["+branchOriginValues[offset]+"]:");
                        if (isTraced(offset))
                        {
                            System.out.println("  Vars:  "+variablesBefore[offset]);
                            System.out.println("  Stack: "+stacksBefore[offset]);
                        }
                    }

                    Instruction instruction = InstructionFactory.create(codeAttribute.code,
                                                                        offset);
                    System.out.println(instruction.toString(offset));

                    if (isTraced(offset))
                    {
                        int initializationOffset = branchTargetFinder.initializationOffset(offset);
                        if (initializationOffset != NONE)
                        {
                            System.out.println("     is to be initialized at ["+initializationOffset+"]");
                        }

                        InstructionOffsetValue branchTargets = branchTargets(offset);
                        if (branchTargets != null)
                        {
                            System.out.println("     has overall been branching to "+branchTargets);
                        }

                        System.out.println("  Vars:  "+variablesAfter[offset]);
                        System.out.println("  Stack: "+stacksAfter[offset]);
                    }

                    offset += instruction.length(offset);
                }
                while (offset < codeAttribute.u4codeLength);
            }

            throw ex;
        }
    }
 
Example 17
public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute)
{
    // Evaluate the instructions, starting at the entry point.
    if (DEBUG)
    {
        System.out.println();
        System.out.println("Partial evaluation: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
        System.out.println("  Max locals = "+codeAttribute.u2maxLocals);
        System.out.println("  Max stack  = "+codeAttribute.u2maxStack);
    }

    // Reuse the existing variables and stack objects, ensuring the right size.
    TracedVariables variables = new TracedVariables(codeAttribute.u2maxLocals);
    TracedStack     stack     = new TracedStack(codeAttribute.u2maxStack);

    // Initialize the reusable arrays and variables.
    initializeArrays(codeAttribute);
    initializeParameters(clazz, method, codeAttribute, variables);

    // Find all instruction offsets,...
    codeAttribute.accept(clazz, method, branchTargetFinder);

    // Start executing the first instruction block.
    evaluateInstructionBlockAndExceptionHandlers(clazz,
                                                 method,
                                                 codeAttribute,
                                                 variables,
                                                 stack,
                                                 0,
                                                 codeAttribute.u4codeLength);

    if (DEBUG_RESULTS)
    {
        System.out.println("Evaluation results:");

        int offset = 0;
        do
        {
            if (isBranchOrExceptionTarget(offset))
            {
                System.out.println("Branch target from ["+branchOriginValues[offset]+"]:");
                if (isTraced(offset))
                {
                    System.out.println("  Vars:  "+variablesBefore[offset]);
                    System.out.println("  Stack: "+stacksBefore[offset]);
                }
            }

            Instruction instruction = InstructionFactory.create(codeAttribute.code,
                                                                offset);
            System.out.println(instruction.toString(offset));

            if (isTraced(offset))
            {
                int initializationOffset = branchTargetFinder.initializationOffset(offset);
                if (initializationOffset != NONE)
                {
                    System.out.println("     is to be initialized at ["+initializationOffset+"]");
                }

                InstructionOffsetValue branchTargets = branchTargets(offset);
                if (branchTargets != null)
                {
                    System.out.println("     has overall been branching to "+branchTargets);
                }

                System.out.println("  Vars:  "+variablesAfter[offset]);
                System.out.println("  Stack: "+stacksAfter[offset]);
            }

            offset += instruction.length(offset);
        }
        while (offset < codeAttribute.u4codeLength);
    }
}