📄 bytecode.java
字号:
/* * Javassist, a Java-bytecode translator toolkit. * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved. * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. Alternatively, the contents of this file may be used under * the terms of the GNU Lesser General Public License Version 2.1 or later. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. */package javassist.bytecode;import javassist.CtClass;import javassist.CtPrimitiveType;class ByteVector implements Cloneable { private byte[] buffer; private int size; public ByteVector() { buffer = new byte[64]; size = 0; } public Object clone() throws CloneNotSupportedException { ByteVector bv = (ByteVector)super.clone(); bv.buffer = (byte[])buffer.clone(); return bv; } public final int getSize() { return size; } public final byte[] copy() { byte[] b = new byte[size]; arraycopy(buffer, b, size); return b; } public int read(int offset) { if (offset < 0 || size <= offset) throw new ArrayIndexOutOfBoundsException(offset); return buffer[offset]; } public void write(int offset, int value) { if (offset < 0 || size <= offset) throw new ArrayIndexOutOfBoundsException(offset); buffer[offset] = (byte)value; } public void add(int code) { addGap(1); buffer[size - 1] = (byte)code; } public void addGap(int length) { if (size + length > buffer.length) { int newSize = size << 1; if (newSize < size + length) newSize = size + length; byte[] newBuf = new byte[newSize]; arraycopy(buffer, newBuf, size); buffer = newBuf; } size += length; } private static void arraycopy(byte[] src, byte[] dest, int size) { for (int i = 0; i < size; i++) dest[i] = src[i]; }}/** * A utility class for producing a bytecode sequence. * * <p>A <code>Bytecode</code> object is an unbounded array * containing bytecode. For example, * * <ul><pre>ConstPool cp = ...; // constant pool table * Bytecode b = new Bytecode(cp, 1, 0); * b.addIconst(3); * b.addReturn(CtClass.intType); * CodeAttribute ca = b.toCodeAttribute();</ul></pre> * * <p>This program produces a Code attribute including a bytecode * sequence: * * <ul><pre>iconst_3 * ireturn</pre></ul> * * @see ConstPool * @see CodeAttribute */public class Bytecode extends ByteVector implements Cloneable, Opcode { /** * Represents the <code>CtClass</code> file using the * constant pool table given to this <code>Bytecode</code> object. */ public static final CtClass THIS = ConstPool.THIS; ConstPool constPool; int maxStack, maxLocals; ExceptionTable tryblocks; private int stackDepth; /** * Constructs a <code>Bytecode</code> object with an empty bytecode * sequence. * * <p>The parameters <code>stacksize</code> and <code>localvars</code> * specify initial values * of <code>max_stack</code> and <code>max_locals</code>. * They can be changed later. * * @param cp constant pool table. * @param stacksize <code>max_stack</code>. * @param localvars <code>max_locals</code>. */ public Bytecode(ConstPool cp, int stacksize, int localvars) { constPool = cp; maxStack = stacksize; maxLocals = localvars; tryblocks = new ExceptionTable(cp); stackDepth = 0; } /** * Constructs a <code>Bytecode</code> object with an empty bytecode * sequence. The initial values of <code>max_stack</code> and * <code>max_locals</code> are zero. * * @param cp constant pool table. * @see Bytecode#setMaxStack(int) * @see Bytecode#setMaxLocals(int) */ public Bytecode(ConstPool cp) { this(cp, 0, 0); } /** * Creates and returns a copy of this object. * The constant pool object is shared between this object * and the cloned object. */ public Object clone() { try { Bytecode bc = (Bytecode)super.clone(); bc.tryblocks = (ExceptionTable)tryblocks.clone(); return bc; } catch (CloneNotSupportedException cnse) { throw new RuntimeException(cnse); } } /** * Gets a constant pool table. */ public ConstPool getConstPool() { return constPool; } /** * Returns <code>exception_table</code>. */ public ExceptionTable getExceptionTable() { return tryblocks; } /** * Converts to a <code>CodeAttribute</code>. */ public CodeAttribute toCodeAttribute() { return new CodeAttribute(constPool, maxStack, maxLocals, get(), tryblocks); } /** * Returns the length of the bytecode sequence. */ public int length() { return getSize(); } /** * Returns the produced bytecode sequence. */ public byte[] get() { return copy(); } /** * Gets <code>max_stack</code>. */ public int getMaxStack() { return maxStack; } /** * Sets <code>max_stack</code>. * * <p>This value may be automatically updated when an instruction * is appended. A <code>Bytecode</code> object maintains the current * stack depth whenever an instruction is added * by <code>addOpcode()</code>. For example, if DUP is appended, * the current stack depth is increased by one. If the new stack * depth is more than <code>max_stack</code>, then it is assigned * to <code>max_stack</code>. However, if branch instructions are * appended, the current stack depth may not be correctly maintained. * * @see #addOpcode(int) */ public void setMaxStack(int size) { maxStack = size; } /** * Gets <code>max_locals</code>. */ public int getMaxLocals() { return maxLocals; } /** * Sets <code>max_locals</code>. */ public void setMaxLocals(int size) { maxLocals = size; } /** * Sets <code>max_locals</code>. * * <p>This computes the number of local variables * used to pass method parameters and sets <code>max_locals</code> * to that number plus <code>locals</code>. * * @param isStatic true if <code>params</code> must be * interpreted as parameters to a static method. * @param params parameter types. * @param locals the number of local variables excluding * ones used to pass parameters. */ public void setMaxLocals(boolean isStatic, CtClass[] params, int locals) { if (!isStatic) ++locals; if (params != null) { CtClass doubleType = CtClass.doubleType; CtClass longType = CtClass.longType; int n = params.length; for (int i = 0; i < n; ++i) { CtClass type = params[i]; if (type == doubleType || type == longType) locals += 2; else ++locals; } } maxLocals = locals; } /** * Increments <code>max_locals</code>. */ public void incMaxLocals(int diff) { maxLocals += diff; } /** * Adds a new entry of <code>exception_table</code>. */ public void addExceptionHandler(int start, int end, int handler, CtClass type) { addExceptionHandler(start, end, handler, constPool.addClassInfo(type)); } /** * Adds a new entry of <code>exception_table</code>. * * @param type the fully-qualified name of a throwable class. */ public void addExceptionHandler(int start, int end, int handler, String type) { addExceptionHandler(start, end, handler, constPool.addClassInfo(type)); } /** * Adds a new entry of <code>exception_table</code>. */ public void addExceptionHandler(int start, int end, int handler, int type) { tryblocks.add(start, end, handler, type); } /** * Returns the length of bytecode sequence * that have been added so far. */ public int currentPc() { return getSize(); } /** * Reads a signed 8bit value at the offset from the beginning of the * bytecode sequence. * * @throws ArrayIndexOutOfBoundsException if offset is invalid. */ public int read(int offset) { return super.read(offset); } /** * Reads a signed 16bit value at the offset from the beginning of the * bytecode sequence. */ public int read16bit(int offset) { int v1 = read(offset); int v2 = read(offset + 1); return (v1 << 8) + (v2 & 0xff); } /** * Reads a signed 32bit value at the offset from the beginning of the * bytecode sequence. */ public int read32bit(int offset) { int v1 = read16bit(offset); int v2 = read16bit(offset + 2); return (v1 << 16) + (v2 & 0xffff); } /** * Writes an 8bit value at the offset from the beginning of the * bytecode sequence. * * @throws ArrayIndexOutOfBoundsException if offset is invalid. */ public void write(int offset, int value) { super.write(offset, value); } /** * Writes an 16bit value at the offset from the beginning of the * bytecode sequence. */ public void write16bit(int offset, int value) { write(offset, value >> 8); write(offset + 1, value); } /** * Writes an 32bit value at the offset from the beginning of the * bytecode sequence. */ public void write32bit(int offset, int value) { write16bit(offset, value >> 16); write16bit(offset + 2, value); } /** * Appends an 8bit value to the end of the bytecode sequence. */ public void add(int code) { super.add(code); } /** * Appends a 32bit value to the end of the bytecode sequence. */ public void add32bit(int value) { add(value >> 24); add(value >> 16); add(value >> 8); add(value); } /** * Appends the length-byte gap to the end of the bytecode sequence. * * @param length the gap length in byte. */ public void addGap(int length) { super.addGap(length); } /** * Appends an 8bit opcode to the end of the bytecode sequence. * The current stack depth is updated. * <code>max_stack</code> is updated if the current stack depth * is the deepest so far. * * <p>Note: some instructions such as INVOKEVIRTUAL does not * update the current stack depth since the increment depends * on the method signature. * <code>growStack()</code> must be explicitly called. */ public void addOpcode(int code) { add(code); growStack(STACK_GROW[code]); } /** * Increases the current stack depth. * It also updates <code>max_stack</code> if the current stack depth * is the deepest so far. * * @param diff the number added to the current stack depth. */ public void growStack(int diff) { setStackDepth(stackDepth + diff); } /** * Returns the current stack depth. */ public int getStackDepth() { return stackDepth; } /** * Sets the current stack depth. * It also updates <code>max_stack</code> if the current stack depth * is the deepest so far. * * @param depth new value. */ public void setStackDepth(int depth) { stackDepth = depth; if (stackDepth > maxStack) maxStack = stackDepth; } /** * Appends a 16bit value to the end of the bytecode sequence. * It never changes the current stack depth. */ public void addIndex(int index) { add(index >> 8); add(index); } /** * Appends ALOAD or (WIDE) ALOAD_<n> * * @param n an index into the local variable array. */ public void addAload(int n) { if (n < 4) addOpcode(42 + n); // aload_<n> else if (n < 0x100) { addOpcode(ALOAD); // aload add(n); } else { addOpcode(WIDE); addOpcode(ALOAD); addIndex(n); } } /** * Appends ASTORE or (WIDE) ASTORE_<n> *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -