📄 classfilewriter.java
字号:
* * @param local * number of local register */ public void addDStore(int local) { xop(ByteCode.DSTORE_0, ByteCode.DSTORE, local); } /** * Store object from stack top into the given local. * * @param local * number of local register */ public void addAStore(int local) { xop(ByteCode.ASTORE_0, ByteCode.ASTORE, local); } /** * Load integer from the given local into stack. * * @param local * number of local register */ public void addILoad(int local) { xop(ByteCode.ILOAD_0, ByteCode.ILOAD, local); } /** * Load long from the given local into stack. * * @param local * number of local register */ public void addLLoad(int local) { xop(ByteCode.LLOAD_0, ByteCode.LLOAD, local); } /** * Load float from the given local into stack. * * @param local * number of local register */ public void addFLoad(int local) { xop(ByteCode.FLOAD_0, ByteCode.FLOAD, local); } /** * Load double from the given local into stack. * * @param local * number of local register */ public void addDLoad(int local) { xop(ByteCode.DLOAD_0, ByteCode.DLOAD, local); } /** * Load object from the given local into stack. * * @param local * number of local register */ public void addALoad(int local) { xop(ByteCode.ALOAD_0, ByteCode.ALOAD, local); } /** * Load "this" into stack. */ public void addLoadThis() { add(ByteCode.ALOAD_0); } private void xop(int shortOp, int op, int local) { switch (local) { case 0: add(shortOp); break; case 1: add(shortOp + 1); break; case 2: add(shortOp + 2); break; case 3: add(shortOp + 3); break; default: add(op, local); } } public int addTableSwitch(int low, int high) { if (DEBUGCODE) { System.out.println("Add " + bytecodeStr(ByteCode.TABLESWITCH) + " " + low + " " + high); } if (low > high) throw new IllegalArgumentException("Bad bounds: " + low + ' ' + high); int newStack = itsStackTop + stackChange(ByteCode.TABLESWITCH); if (newStack < 0 || Short.MAX_VALUE < newStack) badStack(newStack); int entryCount = high - low + 1; int padSize = 3 & ~itsCodeBufferTop; // == 3 - itsCodeBufferTop % 4 int N = addReservedCodeSpace(1 + padSize + 4 * (1 + 2 + entryCount)); int switchStart = N; itsCodeBuffer[N++] = (byte) ByteCode.TABLESWITCH; while (padSize != 0) { itsCodeBuffer[N++] = 0; --padSize; } N += 4; // skip default offset N = putInt32(low, itsCodeBuffer, N); putInt32(high, itsCodeBuffer, N); itsStackTop = (short) newStack; if (newStack > itsMaxStack) itsMaxStack = (short) newStack; if (DEBUGSTACK) { System.out.println("After " + bytecodeStr(ByteCode.TABLESWITCH) + " stack = " + itsStackTop); } return switchStart; } public final void markTableSwitchDefault(int switchStart) { setTableSwitchJump(switchStart, -1, itsCodeBufferTop); } public final void markTableSwitchCase(int switchStart, int caseIndex) { setTableSwitchJump(switchStart, caseIndex, itsCodeBufferTop); } public final void markTableSwitchCase(int switchStart, int caseIndex, int stackTop) { if (!(0 <= stackTop && stackTop <= itsMaxStack)) throw new IllegalArgumentException("Bad stack index: " + stackTop); itsStackTop = (short) stackTop; setTableSwitchJump(switchStart, caseIndex, itsCodeBufferTop); } public void setTableSwitchJump(int switchStart, int caseIndex, int jumpTarget) { if (!(0 <= jumpTarget && jumpTarget <= itsCodeBufferTop)) throw new IllegalArgumentException("Bad jump target: " + jumpTarget); if (!(caseIndex >= -1)) throw new IllegalArgumentException("Bad case index: " + caseIndex); int padSize = 3 & ~switchStart; // == 3 - switchStart % 4 int caseOffset; if (caseIndex < 0) { // default label caseOffset = switchStart + 1 + padSize; } else { caseOffset = switchStart + 1 + padSize + 4 * (3 + caseIndex); } if (!(0 <= switchStart && switchStart <= itsCodeBufferTop - 4 * 4 - padSize - 1)) { throw new IllegalArgumentException(switchStart + " is outside a possible range of tableswitch" + " in already generated code"); } if ((0xFF & itsCodeBuffer[switchStart]) != ByteCode.TABLESWITCH) { throw new IllegalArgumentException(switchStart + " is not offset of tableswitch statement"); } if (!(0 <= caseOffset && caseOffset + 4 <= itsCodeBufferTop)) { // caseIndex >= -1 does not guarantee that caseOffset >= 0 due // to a possible overflow. throw new IllegalArgumentException("Too big case index: " + caseIndex); } // ALERT: perhaps check against case bounds? putInt32(jumpTarget - switchStart, itsCodeBuffer, caseOffset); } public int acquireLabel() { int top = itsLabelTableTop; if (itsLabelTable == null || top == itsLabelTable.length) { if (itsLabelTable == null) { itsLabelTable = new int[MIN_LABEL_TABLE_SIZE]; } else { int[] tmp = new int[itsLabelTable.length * 2]; System.arraycopy(itsLabelTable, 0, tmp, 0, top); itsLabelTable = tmp; } } itsLabelTableTop = top + 1; itsLabelTable[top] = -1; return top | 0x80000000; } public void markLabel(int label) { if (!(label < 0)) throw new IllegalArgumentException("Bad label, no biscuit"); label &= 0x7FFFFFFF; if (label > itsLabelTableTop) throw new IllegalArgumentException("Bad label"); if (itsLabelTable[label] != -1) { throw new IllegalStateException("Can only mark label once"); } itsLabelTable[label] = itsCodeBufferTop; } public void markLabel(int label, short stackTop) { markLabel(label); itsStackTop = stackTop; } public void markHandler(int theLabel) { itsStackTop = 1; markLabel(theLabel); } private int getLabelPC(int label) { if (!(label < 0)) throw new IllegalArgumentException("Bad label, no biscuit"); label &= 0x7FFFFFFF; if (!(label < itsLabelTableTop)) throw new IllegalArgumentException("Bad label"); return itsLabelTable[label]; } private void addLabelFixup(int label, int fixupSite) { if (!(label < 0)) throw new IllegalArgumentException("Bad label, no biscuit"); label &= 0x7FFFFFFF; if (!(label < itsLabelTableTop)) throw new IllegalArgumentException("Bad label"); int top = itsFixupTableTop; if (itsFixupTable == null || top == itsFixupTable.length) { if (itsFixupTable == null) { itsFixupTable = new long[MIN_FIXUP_TABLE_SIZE]; } else { long[] tmp = new long[itsFixupTable.length * 2]; System.arraycopy(itsFixupTable, 0, tmp, 0, top); itsFixupTable = tmp; } } itsFixupTableTop = top + 1; itsFixupTable[top] = ((long) label << 32) | fixupSite; } private void fixLabelGotos() { byte[] codeBuffer = itsCodeBuffer; for (int i = 0; i < itsFixupTableTop; i++) { long fixup = itsFixupTable[i]; int label = (int) (fixup >> 32); int fixupSite = (int) fixup; int pc = itsLabelTable[label]; if (pc == -1) { // Unlocated label throw new RuntimeException(); } // -1 to get delta from instruction start int offset = pc - (fixupSite - 1); if ((short) offset != offset) { throw new RuntimeException( "Program too complex: too big jump offset"); } codeBuffer[fixupSite] = (byte) (offset >> 8); codeBuffer[fixupSite + 1] = (byte) offset; } itsFixupTableTop = 0; } /** * Get the current offset into the code of the current method. * * @return an integer representing the offset */ public int getCurrentCodeOffset() { return itsCodeBufferTop; } public short getStackTop() { return itsStackTop; } public void adjustStackTop(int delta) { int newStack = itsStackTop + delta; if (newStack < 0 || Short.MAX_VALUE < newStack) badStack(newStack); itsStackTop = (short) newStack; if (newStack > itsMaxStack) itsMaxStack = (short) newStack; if (DEBUGSTACK) { System.out.println("After " + "adjustStackTop(" + delta + ")" + " stack = " + itsStackTop); } } private void addToCodeBuffer(int b) { int N = addReservedCodeSpace(1); itsCodeBuffer[N] = (byte) b; } private void addToCodeInt16(int value) { int N = addReservedCodeSpace(2); putInt16(value, itsCodeBuffer, N); } private int addReservedCodeSpace(int size) { if (itsCurrentMethod == null) throw new IllegalArgumentException("No method to add to"); int oldTop = itsCodeBufferTop; int newTop = oldTop + size; if (newTop > itsCodeBuffer.length) { int newSize = itsCodeBuffer.length * 2; if (newTop > newSize) { newSize = newTop; } byte[] tmp = new byte[newSize]; System.arraycopy(itsCodeBuffer, 0, tmp, 0, oldTop); itsCodeBuffer = tmp; } itsCodeBufferTop = newTop; return oldTop; } public void addExceptionHandler(int startLabel, int endLabel, int handlerLabel, String catchClassName) { if ((startLabel & 0x80000000) != 0x80000000) throw new IllegalArgumentException("Bad startLabel"); if ((endLabel & 0x80000000) != 0x80000000) throw new IllegalArgumentException("Bad endLabel"); if ((handlerLabel & 0x80000000) != 0x80000000) throw new IllegalArgumentException("Bad handlerLabel"); /* * If catchClassName is null, use 0 for the catch_type_index; which * means catch everything. (Even when the verifier has let you throw * something other than a Throwable.) */ short catch_type_index = (catchClassName == null) ? 0 : itsConstantPool .addClass(catchClassName); ExceptionTableEntry newEntry = new ExceptionTableEntry(startLabel, endLabel, handlerLabel, catch_type_index); int N = itsExceptionTableTop; if (N == 0) { itsExceptionTable = new ExceptionTableEntry[ExceptionTableSize]; } else if (N == itsExceptionTable.length) { ExceptionTableEntry[] tmp = new ExceptionTableEntry[N * 2]; System.arraycopy(itsExceptionTable, 0, tmp, 0, N); itsExceptionTable = tmp; } itsExceptionTable[N] = newEntry; itsExceptionTableTop = N + 1; } public void addLineNumberEntry(short lineNumber) { if (itsCurrentMethod == null) throw new IllegalArgumentException("No method to stop"); int N = itsLineNumberTableTop; if (N == 0) { itsLineNumberTable = new int[LineNumberTableSize]; } else if (N == itsLineNumberTable.length) { int[] tmp = new int[N * 2]; System.arraycopy(itsLineNumberTable, 0, tmp, 0, N); itsLineNumberTable = tmp; } itsLineNumberTable[N] = (itsCodeBufferTop << 16) + lineNumber; itsLineNumberTableTop = N + 1; } /** * Write the class file to the OutputStream. * * @param oStream * the stream to write to * @throws IOException * if writing to the stream produces an exception */ public void write(OutputStream oStream) throws IOException { byte[] array = toByteArray(); oStream.write(array); } private int getWriteSize() { int size = 0; if (itsSourceFileNameIndex != 0) { itsConstantPool.addUtf8("SourceFile"); } size += 8; // writeLong(FileHeaderConstant); size += itsConstantPool.getWriteSize(); size += 2; // writeShort(itsFlags); size += 2; // writeShort(itsThisClassIndex); size += 2; // writeShort(itsSuperClassIndex); size += 2; // writeShort(itsInterfaces.size()); size += 2 * itsInterfaces.size(); size += 2; // writeShort(itsFields.size()); for (int i = 0; i < itsFields.size(); i++) { size += ((ClassFileField) (itsFields.get(i))).getWriteSize(); } size += 2; // writeShort(itsMethods.size()); for (int i = 0; i < itsMethods.size(); i++) { size += ((ClassFileMethod) (itsMethods.get(i))).getWriteSize(); } if (itsSourceFileNameIndex != 0) { size += 2; // writeShort(1); attributes count size += 2; // writeShort(sourceFileAttributeNameIndex); size += 4; // writeInt(2); size += 2; // writeShort(itsSourceFileNameIndex); } else { size += 2; // out.writeShort(0); no attributes } return size; } /** * Get the class file as array of bytesto the OutputStream. */ public byte[] toByteArray() { int dataSize = getWriteSize(); byte[] data = new byte[dataSize]; int offset = 0; short sourceFileAttributeNameIndex = 0; if (itsSourceFileNameIndex != 0) { sourceFileAttributeNameIndex = itsConstantPool .addUtf8("SourceFile"); } offset = putInt64(FileHeaderConstant, data, offset); offset = itsConstantPool.write(data, offset); offset = putInt16(itsFlags, data, offset); offset = putInt16(itsThisClassIndex, data, offset); offset = putInt16(itsSuperClassIndex, data, offset); offset = putInt16(itsInterfaces.size(), data, offset); for (int i = 0; i < itsInterfaces.size(); i++) { int interfaceIndex = ((Short) (itsInterfaces.get(i))).shortValue(); offset = putInt16(interfaceIndex, data, offset); } offset = putInt16(itsFields.size(), data, offset); for (int i = 0; i < itsFields.size(); i++) { ClassFileField field = (ClassFileField) itsFields.get(i); offset = field.write(data, offset); } offset = putInt16(itsMethods.size(), data, offset); for (int i = 0; i < itsMethods.size(); i++) { ClassFileMethod method = (ClassFileMethod) itsMethods.get(i); offset = method.write(data, offset); } if (itsSourceFileNameIndex != 0) { offset = putInt16(1, data, offset); // attributes count offset = putInt16(sourceFileAttributeNameIndex, data, offset); offset = putInt32(2, data, offset); offset = putInt16(itsSourceFileNameIndex, data, offset);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -