⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 codeinsertion.java

📁 Java Bytecode Editor 是一个 JAVA 的字节码反汇编和修改器。它可以很方便的修改已经编译成 Class 文件的 JAVA 文件。
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public
    License as published by the Free Software Foundation; either
    version 2 of the license, or (at your option) any later version.
*/

package org.gjt.jclasslib.bytecode;

import org.gjt.jclasslib.structures.InvalidByteCodeException;
import org.gjt.jclasslib.structures.attributes.*;

import java.util.*;

/**
    Contains all information necessary to insert code into a
    method. Allows for pre and post insertions. The core method
    to perform code insertions is the static <tt>apply</tt> method.

    @author <a href="mailto:jclasslib@ej-technologies.com">Ingo Kegel</a>
    @version $Revision: 1.2 $ $Date: 2006/09/04 15:43:18 $
*/
public class CodeInsertion {


    /**
        Merge two code insertions into one.
        @param position the position of the resulting <tt>CodeInsertion</tt>
        @param shiftTarget should offsets of branch instructions pointing to 
                           the position of the resulting code insertion
                           be shifted or point to the beginning of the 
                           inserted code.
        @param inner the inner <tt>CodeInsertion</tt>
        @param outer the outer <tt>CodeInsertion</tt>
        @return the resulting <tt>CodeInsertion</tt>
    */
    public static CodeInsertion merge(int position,
                                      boolean shiftTarget,
                                      CodeInsertion inner,
                                      CodeInsertion outer)
    {

        if (outer == null) {
            return inner;
        }
        if (inner == null) {
            return outer;
        }

        AbstractInstruction[] preInstructions = mergeInstructions(outer.preInstructions, inner.preInstructions);
        AbstractInstruction[] postInstructions = mergeInstructions(inner.postInstructions, outer.postInstructions);

        CodeInsertion codeInsertion =
            new CodeInsertion(position,
                              preInstructions,
                              postInstructions,
                              shiftTarget);

        return codeInsertion;
    }

    /**
        Merge two arrays of instructions into one.
        @param firstInstructions the head array of type <tt>AbstractInstruction</tt>
        @param lastInstructions the tail array of type <tt>AbstractInstruction</tt>
        @return the merged array of type <tt>AbstractInstruction[]</tt>
    */
    public static AbstractInstruction[] mergeInstructions(AbstractInstruction[] firstInstructions,
                                                          AbstractInstruction[] lastInstructions)
    {
        if (firstInstructions== null) {
            return lastInstructions;
        }
        if (lastInstructions == null) {
            return firstInstructions;
        }

        AbstractInstruction[] mergedInstructions = new AbstractInstruction[firstInstructions.length + lastInstructions.length];
        System.arraycopy(firstInstructions, 0, mergedInstructions, 0, firstInstructions.length);
        System.arraycopy(lastInstructions, 0, mergedInstructions, firstInstructions.length, lastInstructions.length);

        return mergedInstructions;
    }

    /**
        Apply a list of <tt>CodeInsertion</tt>s to a list of instructions
        such as the one supplied by a <tt>ByteCodeReader</tt>. Offsets
        of branch instructions will be adapted to point to the original
        instructions. Exception and line number tables in the associated 
        <tt>CodeAttribute</tt>will also be updated.
     
        @param instructions the list of instructions which is to be treated
                            with the <tt>CodeInsertion</tt>s. This list
                            and the resulting instructions will not be usable
                            after the method is finished. If you need to 
                            reuse the original instructions, you have to pass
                            a deep-cloned list into this method.
        @param codeInsertions the list of codeInsertions which is to be applied to
                              the list of instructions.
        @param codeAttribute the <tt>CodeAttribute</tt> pertaining to the supplied 
                             list of instructions.
        @return the resulting list of instructions
        @throws InvalidByteCodeException
     */
    public static List apply(List instructions,
                             List codeInsertions,
                             CodeAttribute codeAttribute)

        throws InvalidByteCodeException
    {
        int instructionCount = instructions.size();
        int[] transformedIndices = new int[instructionCount];
        for (int i = 0; i < instructionCount; i++) {
            transformedIndices[i] = i;
        }

        List newInstructions = insertCode(instructions,
                                          codeInsertions,
                                          transformedIndices);

        int[] oldOffsets = new int[instructionCount];
        for (int i = 0; i < instructionCount; i++) {
            oldOffsets[i] = ((AbstractInstruction)instructions.get(i)).getOffset();
        }
        int[] newOffsets = new int[newInstructions.size()];
        calculateOffsets(newInstructions, newOffsets);


        adjustOffsets(instructions,
                      newInstructions,
                      oldOffsets,
                      newOffsets,
                      transformedIndices);

        if (codeAttribute != null) {
            adjustExceptionTable(oldOffsets,
                                 newOffsets,
                                 transformedIndices,
                                 codeAttribute);

            adjustLineNumberTable(oldOffsets,
                                  newOffsets,
                                  transformedIndices,
                                  codeAttribute);
        }

        applyOffsets(newInstructions, newOffsets);
        return newInstructions;
    }

    private static List insertCode(List instructions,
                                   List codeInsertions,
                                   int[] transformedIndices)
    {
        int instructionCount = instructions.size();
        int insertionCount = codeInsertions.size();

        int newSize = calculateNewSize(instructions, codeInsertions);
        List<Object> newInstructions = new ArrayList<Object>(newSize);

        int currentInsertionIndex = 0;
        CodeInsertion currentInsertion = (CodeInsertion)codeInsertions.get(0);
        for (int i = 0; i < instructionCount; i++) {
            if (currentInsertion.getPosition() < i && currentInsertionIndex < insertionCount - 1) {
                ++currentInsertionIndex;
                currentInsertion = (CodeInsertion)codeInsertions.get(currentInsertionIndex);
            }
            int addedBefore = 0;
            int addedAfter = 0;
            if (currentInsertion.getPosition() == i) {
                addedBefore = addInstructions(newInstructions, currentInsertion.getPreInstructions());
            }
            newInstructions.add(instructions.get(i));
            if (currentInsertion.getPosition() == i) {
                addedAfter = addInstructions(newInstructions, currentInsertion.getPostInstructions());
            }
            if (addedBefore > 0 || addedAfter > 0) {
                shiftIndices(i, addedBefore, addedAfter, transformedIndices, currentInsertion.isShiftTarget());
            }
        }

        return newInstructions;
    }

    private static int calculateNewSize(List instructions, List codeInsertions) {

        int insertionCount = codeInsertions.size();
        int newSize = instructions.size();
        for (int i = 0; i < insertionCount; i++) {
            CodeInsertion insertion = (CodeInsertion)codeInsertions.get(i);

            AbstractInstruction[] preInstructions = insertion.getPreInstructions();
            if (preInstructions != null) {
                newSize += preInstructions.length;
            }
            AbstractInstruction[] postInstructions = insertion.getPostInstructions();
            if (postInstructions != null) {
                newSize += postInstructions.length;
            }
        }
        return newSize;
    }

    private static void shiftIndices(int currentIndex,
                                     int addedBefore,
                                     int addedAfter,
                                     int[] transformedIndices,
                                     boolean shiftTarget)
    {
        if (!shiftTarget) {
            transformedIndices[currentIndex] += addedBefore;
        }
        for (int i = currentIndex + 1; i < transformedIndices.length; i++) {
            transformedIndices[i] += addedBefore + addedAfter;
        }
    }

    private static int addInstructions(List<Object> newInstructions,
                                       AbstractInstruction[] insertedInstructions)
    {
        if (insertedInstructions != null) {
            for (int i = 0; i < insertedInstructions.length; i++) {
                newInstructions.add(insertedInstructions[i]);
            }
            return insertedInstructions.length;
        } else {
            return 0;
        }
    }

    private static void calculateOffsets(List instructions,
                                         int[] offsets)
    {
        int instructionCount = instructions.size();
        int currentOffset = 0;
        for (int i = 0; i < instructionCount; i++) {
            offsets[i] = currentOffset;

            AbstractInstruction instr = (AbstractInstruction)instructions.get(i);

            int currentSize;
            if (instr instanceof PaddedInstruction) {
                currentSize = ((PaddedInstruction)instr).getPaddedSize(currentOffset);
            } else {
                currentSize = instr.getSize();
            }
            currentOffset += currentSize;
        }
    }

    private static void applyOffsets(List instructions, int[] offsets) {
        int instructionCount = instructions.size();
        for (int i = 0; i < instructionCount; i++) {
            AbstractInstruction instr = (AbstractInstruction)instructions.get(i);
            instr.setOffset(offsets[i]);
        }
    }

    private static void adjustOffsets(List instructions,
                                      List newInstructions,
                                      int[] oldOffsets,
                                      int[] newOffsets,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -