|
Scala example source code file (JCode.java)
The Scala JCode.java source code/* FJBG -- Fast Java Bytecode Generator * Copyright 2002-2011 LAMP/EPFL * @author Michel Schinz */ package ch.epfl.lamp.fjbg; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.*; import ch.epfl.lamp.util.ByteArray; /** * List of instructions, to which Java byte-code instructions can be added. * * @author Michel Schinz, Thomas Friedli * @version 1.0 */ public class JCode { protected boolean frozen = false; protected final FJBGContext context; protected final JMethod owner; protected final ByteArray codeArray; protected final LinkedList/*<ExceptionHandler>*/ exceptionHandlers = new LinkedList(); protected final JConstantPool pool; protected final ArrayList/*<OffsetToPatch>*/ offsetToPatch = new ArrayList(); protected static int UNKNOWN_STACK_SIZE = Integer.MIN_VALUE; protected int maxStackSize = UNKNOWN_STACK_SIZE; protected int[] stackProduction = null; protected int[] stackSizes; protected JCode(FJBGContext context, JClass clazz, JMethod owner) { this.context = context; this.pool = clazz.getConstantPool(); this.owner = owner; this.codeArray = new ByteArray(); } protected JCode(FJBGContext context, JClass clazz, JMethod owner, DataInputStream stream) throws IOException { this.context = context; this.pool = clazz.getConstantPool(); this.owner = owner; owner.setCode(this); int size = stream.readInt(); if (size >= 65536) // section 4.10 throw new Error("code size must be less than 65536: " + size); this.codeArray = new ByteArray(stream, size); } /** * Gets the program counter, which is defined as the address of the * next instruction. * @return The int representing the value of the program counter */ public int getPC() { return codeArray.getSize(); } /** * Gets the size of the code * @return The number of bytes of the code */ public int getSize() { return codeArray.getSize(); } /** * Gets the method to which the code belongs * @return The method to which the code belongs */ public JMethod getOwner() { return owner; } // Stack size public int getMaxStackSize() { if (maxStackSize == UNKNOWN_STACK_SIZE) maxStackSize = computeMaxStackSize(); return maxStackSize; } // Freezing ////////////////////////////////////////////////////////////////////// public void freeze() throws OffsetTooBigException { assert !frozen; patchAllOffset(); codeArray.freeze(); frozen = true; } // Attributes ////////////////////////////////////////////////////////////////////// protected final LinkedList/*<JAttribute>*/ attributes = new LinkedList(); public void addAttribute(JAttribute attr) { attributes.add(attr); } public List/*<JAttribute>*/ getAttributes() { return attributes; } // Emitting code ////////////////////////////////////////////////////////////////////// public void emit(JOpcode opcode) { setStackProduction(getPC(), opcode); codeArray.addU1(opcode.code); } public void emitNOP() { emit(JOpcode.NOP); } // Constant loading. public void emitACONST_NULL() { emit(JOpcode.ACONST_NULL); } public void emitICONST_M1() { emit(JOpcode.ICONST_M1); } public void emitICONST_0() { emit(JOpcode.ICONST_0); } public void emitICONST_1() { emit(JOpcode.ICONST_1); } public void emitICONST_2() { emit(JOpcode.ICONST_2); } public void emitICONST_3() { emit(JOpcode.ICONST_3); } public void emitICONST_4() { emit(JOpcode.ICONST_4); } public void emitICONST_5() { emit(JOpcode.ICONST_5); } public void emitLCONST_0() { emit(JOpcode.LCONST_0); } public void emitLCONST_1() { emit(JOpcode.LCONST_1); } public void emitFCONST_0() { emit(JOpcode.FCONST_0); } public void emitFCONST_1() { emit(JOpcode.FCONST_1); } public void emitFCONST_2() { emit(JOpcode.FCONST_2); } public void emitDCONST_0() { emit(JOpcode.DCONST_0); } public void emitDCONST_1() { emit(JOpcode.DCONST_1); } public void emitBIPUSH(int b) { emitU1(JOpcode.BIPUSH, b); } public void emitSIPUSH(int s) { emitU2(JOpcode.SIPUSH, s); } public void emitLDC(int value) { emitU1(JOpcode.LDC, pool.addInteger(value)); } public void emitLDC(float value) { emitU1(JOpcode.LDC, pool.addFloat(value)); } public void emitLDC(String value) { emitU1(JOpcode.LDC, pool.addString(value)); } public void emitLDC_W(int value) { emitU1(JOpcode.LDC_W, pool.addInteger(value)); } public void emitLDC_W(float value) { emitU1(JOpcode.LDC_W, pool.addFloat(value)); } public void emitLDC_W(String value) { emitU1(JOpcode.LDC_W, pool.addString(value)); } public void emitLDC2_W(long value) { emitU2(JOpcode.LDC2_W, pool.addLong(value)); } public void emitLDC2_W(double value) { emitU2(JOpcode.LDC2_W, pool.addDouble(value)); } // Loading variables. public void emitILOAD(int index) { emitU1(JOpcode.ILOAD, index); } public void emitLLOAD(int index) { emitU1(JOpcode.LLOAD, index); } public void emitFLOAD(int index) { emitU1(JOpcode.FLOAD, index); } public void emitDLOAD(int index) { emitU1(JOpcode.DLOAD, index); } public void emitALOAD(int index) { emitU1(JOpcode.ALOAD, index); } public void emitILOAD_0() { emit(JOpcode.ILOAD_0); } public void emitILOAD_1() { emit(JOpcode.ILOAD_1); } public void emitILOAD_2() { emit(JOpcode.ILOAD_2); } public void emitILOAD_3() { emit(JOpcode.ILOAD_3); } public void emitLLOAD_0() { emit(JOpcode.LLOAD_0); } public void emitLLOAD_1() { emit(JOpcode.LLOAD_1); } public void emitLLOAD_2() { emit(JOpcode.LLOAD_2); } public void emitLLOAD_3() { emit(JOpcode.LLOAD_3); } public void emitFLOAD_0() { emit(JOpcode.FLOAD_0); } public void emitFLOAD_1() { emit(JOpcode.FLOAD_1); } public void emitFLOAD_2() { emit(JOpcode.FLOAD_2); } public void emitFLOAD_3() { emit(JOpcode.FLOAD_3); } public void emitDLOAD_0() { emit(JOpcode.DLOAD_0); } public void emitDLOAD_1() { emit(JOpcode.DLOAD_1); } public void emitDLOAD_2() { emit(JOpcode.DLOAD_2); } public void emitDLOAD_3() { emit(JOpcode.DLOAD_3); } public void emitALOAD_0() { emit(JOpcode.ALOAD_0); } public void emitALOAD_1() { emit(JOpcode.ALOAD_1); } public void emitALOAD_2() { emit(JOpcode.ALOAD_2); } public void emitALOAD_3() { emit(JOpcode.ALOAD_3); } public void emitIALOAD() { emit(JOpcode.IALOAD); } public void emitLALOAD() { emit(JOpcode.LALOAD); } public void emitFALOAD() { emit(JOpcode.FALOAD); } public void emitDALOAD() { emit(JOpcode.DALOAD); } public void emitAALOAD() { emit(JOpcode.AALOAD); } public void emitBALOAD() { emit(JOpcode.BALOAD); } public void emitCALOAD() { emit(JOpcode.CALOAD); } public void emitSALOAD() { emit(JOpcode.SALOAD); } // Storing variables. public void emitISTORE(int index) { emitU1(JOpcode.ISTORE, index); } public void emitLSTORE(int index) { emitU1(JOpcode.LSTORE, index); } public void emitFSTORE(int index) { emitU1(JOpcode.FSTORE, index); } public void emitDSTORE(int index) { emitU1(JOpcode.DSTORE, index); } public void emitASTORE(int index) { emitU1(JOpcode.ASTORE, index); } public void emitISTORE_0() { emit(JOpcode.ISTORE_0); } public void emitISTORE_1() { emit(JOpcode.ISTORE_1); } public void emitISTORE_2() { emit(JOpcode.ISTORE_2); } public void emitISTORE_3() { emit(JOpcode.ISTORE_3); } public void emitLSTORE_0() { emit(JOpcode.LSTORE_0); } public void emitLSTORE_1() { emit(JOpcode.LSTORE_1); } public void emitLSTORE_2() { emit(JOpcode.LSTORE_2); } public void emitLSTORE_3() { emit(JOpcode.LSTORE_3); } public void emitFSTORE_0() { emit(JOpcode.FSTORE_0); } public void emitFSTORE_1() { emit(JOpcode.FSTORE_1); } public void emitFSTORE_2() { emit(JOpcode.FSTORE_2); } public void emitFSTORE_3() { emit(JOpcode.FSTORE_3); } public void emitDSTORE_0() { emit(JOpcode.DSTORE_0); } public void emitDSTORE_1() { emit(JOpcode.DSTORE_1); } public void emitDSTORE_2() { emit(JOpcode.DSTORE_2); } public void emitDSTORE_3() { emit(JOpcode.DSTORE_3); } public void emitASTORE_0() { emit(JOpcode.ASTORE_0); } public void emitASTORE_1() { emit(JOpcode.ASTORE_1); } public void emitASTORE_2() { emit(JOpcode.ASTORE_2); } public void emitASTORE_3() { emit(JOpcode.ASTORE_3); } public void emitIASTORE() { emit(JOpcode.IASTORE); } public void emitLASTORE() { emit(JOpcode.LASTORE); } public void emitFASTORE() { emit(JOpcode.FASTORE); } public void emitDASTORE() { emit(JOpcode.DASTORE); } public void emitAASTORE() { emit(JOpcode.AASTORE); } public void emitBASTORE() { emit(JOpcode.BASTORE); } public void emitCASTORE() { emit(JOpcode.CASTORE); } public void emitSASTORE() { emit(JOpcode.SASTORE); } // Stack manipulation. public void emitPOP() { emit(JOpcode.POP); } public void emitPOP2() { emit(JOpcode.POP2); } public void emitDUP() { emit(JOpcode.DUP); } public void emitDUP_X1() { emit(JOpcode.DUP_X1); } public void emitDUP_X2() { emit(JOpcode.DUP_X2); } public void emitDUP2() { emit(JOpcode.DUP2); } public void emitDUP2_X1() { emit(JOpcode.DUP2_X1); } public void emitDUP2_X2() { emit(JOpcode.DUP2_X2); } public void emitSWAP() { emit(JOpcode.SWAP); } // Artithmetic and logic operations. public void emitIADD() { emit(JOpcode.IADD); } public void emitLADD() { emit(JOpcode.LADD); } public void emitFADD() { emit(JOpcode.FADD); } public void emitDADD() { emit(JOpcode.DADD); } public void emitISUB() { emit(JOpcode.ISUB); } public void emitLSUB() { emit(JOpcode.LSUB); } public void emitFSUB() { emit(JOpcode.FSUB); } public void emitDSUB() { emit(JOpcode.DSUB); } public void emitIMUL() { emit(JOpcode.IMUL); } public void emitLMUL() { emit(JOpcode.LMUL); } public void emitFMUL() { emit(JOpcode.FMUL); } public void emitDMUL() { emit(JOpcode.DMUL); } public void emitIDIV() { emit(JOpcode.IDIV); } public void emitLDIV() { emit(JOpcode.LDIV); } public void emitFDIV() { emit(JOpcode.FDIV); } public void emitDDIV() { emit(JOpcode.DDIV); } public void emitIREM() { emit(JOpcode.IREM); } public void emitLREM() { emit(JOpcode.LREM); } public void emitFREM() { emit(JOpcode.FREM); } public void emitDREM() { emit(JOpcode.DREM); } public void emitINEG() { emit(JOpcode.INEG); } public void emitLNEG() { emit(JOpcode.LNEG); } public void emitFNEG() { emit(JOpcode.FNEG); } public void emitDNEG() { emit(JOpcode.DNEG); } public void emitISHL() { emit(JOpcode.ISHL); } public void emitLSHL() { emit(JOpcode.LSHL); } public void emitISHR() { emit(JOpcode.ISHR); } public void emitLSHR() { emit(JOpcode.LSHR); } public void emitIUSHR() { emit(JOpcode.IUSHR); } public void emitLUSHR() { emit(JOpcode.LUSHR); } public void emitIAND() { emit(JOpcode.IAND); } public void emitLAND() { emit(JOpcode.LAND); } public void emitIOR() { emit(JOpcode.IOR); } public void emitLOR() { emit(JOpcode.LOR); } public void emitIXOR() { emit(JOpcode.IXOR); } public void emitLXOR() { emit(JOpcode.LXOR); } public void emitIINC(int index, int increment) { emitU1U1(JOpcode.IINC, index, increment); } // (Numeric) type conversions. public void emitI2L() { emit(JOpcode.I2L); } public void emitI2F() { emit(JOpcode.I2F); } public void emitI2D() { emit(JOpcode.I2D); } public void emitL2I() { emit(JOpcode.L2I); } public void emitL2F() { emit(JOpcode.L2F); } public void emitL2D() { emit(JOpcode.L2D); } public void emitF2I() { emit(JOpcode.F2I); } public void emitF2L() { emit(JOpcode.F2L); } public void emitF2D() { emit(JOpcode.F2D); } public void emitD2I() { emit(JOpcode.D2I); } public void emitD2L() { emit(JOpcode.D2L); } public void emitD2F() { emit(JOpcode.D2F); } public void emitI2B() { emit(JOpcode.I2B); } public void emitI2C() { emit(JOpcode.I2C); } public void emitI2S() { emit(JOpcode.I2S); } // Comparisons and tests. public void emitLCMP() { emit(JOpcode.LCMP); } public void emitFCMPL() { emit(JOpcode.FCMPL); } public void emitFCMPG() { emit(JOpcode.FCMPG); } public void emitDCMPL() { emit(JOpcode.DCMPL); } public void emitDCMPG() { emit(JOpcode.DCMPG); } protected void emitGenericIF(JOpcode opcode, Label label) throws OffsetTooBigException { emitU2(opcode, label.getOffset16(getPC() + 1, getPC())); } public void emitIFEQ(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IFEQ, label); } public void emitIFEQ(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IFEQ, targetPC - getPC()); } public void emitIFEQ() { emitU2(JOpcode.IFEQ, 0); } public void emitIFNE(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IFNE, label); } public void emitIFNE(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IFNE, targetPC - getPC()); } public void emitIFNE() { emitU2(JOpcode.IFNE, 0); } public void emitIFLT(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IFLT, label); } public void emitIFLT(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IFLT, targetPC - getPC()); } public void emitIFLT() { emitU2(JOpcode.IFLT, 0); } public void emitIFGE(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IFGE, label); } public void emitIFGE(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IFGE, targetPC - getPC()); } public void emitIFGE() { emitU2(JOpcode.IFGE, 0); } public void emitIFGT(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IFGT, label); } public void emitIFGT(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IFGT, targetPC - getPC()); } public void emitIFGT() { emitU2(JOpcode.IFGT, 0); } public void emitIFLE(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IFLE, label); } public void emitIFLE(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IFLE, targetPC - getPC()); } public void emitIFLE() { emitU2(JOpcode.IFLE, 0); } public void emitIF_ICMPEQ(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IF_ICMPEQ, label); } public void emitIF_ICMPEQ(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IF_ICMPEQ, targetPC - getPC()); } public void emitIF_ICMPEQ() { emitU2(JOpcode.IF_ICMPEQ, 0); } public void emitIF_ICMPNE(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IF_ICMPNE, label); } public void emitIF_ICMPNE(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IF_ICMPNE, targetPC - getPC()); } public void emitIF_ICMPNE() { emitU2(JOpcode.IF_ICMPNE, 0); } public void emitIF_ICMPLT(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IF_ICMPLT, label); } public void emitIF_ICMPLT(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IF_ICMPLT, targetPC - getPC()); } public void emitIF_ICMPLT() { emitU2(JOpcode.IF_ICMPLT, 0); } public void emitIF_ICMPGE(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IF_ICMPGE, label); } public void emitIF_ICMPGE(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IF_ICMPGE, targetPC - getPC()); } public void emitIF_ICMPGE() { emitU2(JOpcode.IF_ICMPGE, 0); } public void emitIF_ICMPGT(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IF_ICMPGT, label); } public void emitIF_ICMPGT(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IF_ICMPGT, targetPC - getPC()); } public void emitIF_ICMPGT() { emitU2(JOpcode.IF_ICMPGT, 0); } public void emitIF_ICMPLE(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IF_ICMPLE, label); } public void emitIF_ICMPLE(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IF_ICMPLE, targetPC - getPC()); } public void emitIF_ICMPLE() { emitU2(JOpcode.IF_ICMPLE, 0); } public void emitIF_ACMPEQ(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IF_ACMPEQ, label); } public void emitIF_ACMPEQ(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IF_ACMPEQ, targetPC - getPC()); } public void emitIF_ACMPEQ() { emitU2(JOpcode.IF_ACMPEQ, 0); } public void emitIF_ACMPNE(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IF_ACMPNE, label); } public void emitIF_ACMPNE(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IF_ACMPNE, targetPC - getPC()); } public void emitIF_ACMPNE() { emitU2(JOpcode.IF_ACMPNE, 0); } public void emitIFNULL(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IFNULL, label); } public void emitIFNULL(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IFNULL, targetPC - getPC()); } public void emitIFNULL() { emitU2(JOpcode.IFNULL, 0); } public void emitIFNONNULL(Label label) throws OffsetTooBigException { emitGenericIF(JOpcode.IFNONNULL, label); } public void emitIFNONNULL(int targetPC) throws OffsetTooBigException { emitU2(JOpcode.IFNONNULL, targetPC - getPC()); } public void emitIFNONNULL() { emitU2(JOpcode.IFNONNULL, 0); } public void emitGOTO(Label label) throws OffsetTooBigException { emitU2(JOpcode.GOTO, label.getOffset16(getPC() + 1, getPC())); } public void emitGOTO(int targetPC) throws OffsetTooBigException { int offset = targetPC - getPC(); checkOffset16(offset); emitU2(JOpcode.GOTO, offset); } public void emitGOTO() { emitU2(JOpcode.GOTO, 0); } public void emitGOTO_W(Label label) { emitU4(JOpcode.GOTO_W, label.getOffset32(getPC() + 1, getPC())); } public void emitGOTO_W(int targetPC) { emitU4(JOpcode.GOTO_W, targetPC - getPC()); } public void emitGOTO_W() { emitU4(JOpcode.GOTO_W, 0); } public void emitJSR(Label label) throws OffsetTooBigException { emitU2(JOpcode.JSR, label.getOffset16(getPC() + 1, getPC())); } public void emitJSR(int targetPC) { emitU2(JOpcode.JSR, targetPC - getPC()); } public void emitJSR() { emitU2(JOpcode.JSR, 0); } public void emitJSR_W(Label label) { emitU4(JOpcode.JSR_W, label.getOffset32(getPC() + 1, getPC())); } public void emitJSR_W(int targetPC) { emitU4(JOpcode.JSR_W, targetPC - getPC()); } public void emitJSR_W() { emitU4(JOpcode.JSR_W, 0); } /* public void emitRET(Label label) throws OffsetTooBigException { emitU2(JOpcode.RET, label.getOffset16(getPC() + 1, getPC())); } public void emitRET(int targetPC) { emitU1(JOpcode.RET, targetPC); } public void emitRET() { emitU1(JOpcode.RET, 0); } */ public void emitRET(int index) { emitU1(JOpcode.RET, index); } public void emitRET(JLocalVariable var) { emitRET(var.getIndex()); } public void emitTABLESWITCH(int[] keys, Label[] branches, Label defaultBranch) { assert keys.length == branches.length; int low = keys[0], high = keys[keys.length - 1]; int instrPC = getPC(); setStackProduction(instrPC, JOpcode.TABLESWITCH); codeArray.addU1(JOpcode.cTABLESWITCH); while (getPC() % 4 != 0) codeArray.addU1(0); codeArray.addU4(defaultBranch.getOffset32(getPC(), instrPC)); codeArray.addU4(low); codeArray.addU4(high); for (int i = 0; i < branches.length; i++) { assert keys[i] == low + i; codeArray.addU4(branches[i].getOffset32(getPC(), instrPC)); } } public void emitLOOKUPSWITCH(int[] keys, Label[] branches, Label defaultBranch) { assert keys.length == branches.length; int instrPC = getPC(); setStackProduction(getPC(), JOpcode.LOOKUPSWITCH); codeArray.addU1(JOpcode.cLOOKUPSWITCH); while (getPC() % 4 != 0) codeArray.addU1(0); codeArray.addU4(defaultBranch.getOffset32(getPC(), instrPC)); codeArray.addU4(branches.length); for (int i = 0; i < branches.length; i++) { codeArray.addU4(keys[i]); codeArray.addU4(branches[i].getOffset32(getPC(), instrPC)); } } public void emitIRETURN() { emit(JOpcode.IRETURN); } public void emitLRETURN() { emit(JOpcode.LRETURN); } public void emitFRETURN() { emit(JOpcode.FRETURN); } public void emitDRETURN() { emit(JOpcode.DRETURN); } public void emitARETURN() { emit(JOpcode.ARETURN); } public void emitRETURN() { emit(JOpcode.RETURN); } // Field access public void emitGETSTATIC(String className, String name, JType type) { setStackProduction(getPC(), type.getSize()); int index = pool.addFieldRef(className, name, type.getSignature()); emitU2(JOpcode.GETSTATIC, index); } public void emitPUTSTATIC(String className, String name, JType type) { setStackProduction(getPC(), -type.getSize()); int index = pool.addFieldRef(className, name, type.getSignature()); emitU2(JOpcode.PUTSTATIC, index); } public void emitGETFIELD(String className, String name, JType type) { setStackProduction(getPC(), type.getSize() - 1); int index = pool.addFieldRef(className, name, type.getSignature()); emitU2(JOpcode.GETFIELD, index); } public void emitPUTFIELD(String className, String name, JType type) { setStackProduction(getPC(), -(type.getSize() + 1)); int index = pool.addFieldRef(className, name, type.getSignature()); emitU2(JOpcode.PUTFIELD, index); } // Method invocation public void emitINVOKEVIRTUAL(String className, String name, JMethodType type) { setStackProduction(getPC(), type.getProducedStack() - 1); int index = pool.addClassMethodRef(className, name, type.getSignature()); emitU2(JOpcode.INVOKEVIRTUAL, index); } public void emitINVOKESPECIAL(String className, String name, JMethodType type) { setStackProduction(getPC(), type.getProducedStack() - 1); int index = pool.addClassMethodRef(className, name, type.getSignature()); emitU2(JOpcode.INVOKESPECIAL, index); } public void emitINVOKESTATIC(String className, String name, JMethodType type) { setStackProduction(getPC(), type.getProducedStack()); int index = pool.addClassMethodRef(className, name, type.getSignature()); emitU2(JOpcode.INVOKESTATIC, index); } public void emitINVOKEINTERFACE(String className, String name, JMethodType type) { setStackProduction(getPC(), type.getProducedStack() - 1); int index = pool.addInterfaceMethodRef(className, name, type.getSignature()); emitU2U1U1(JOpcode.INVOKEINTERFACE, index, type.getArgsSize() + 1, 0); } // Object creation public void emitNEW(String className) { emitU2(JOpcode.NEW, pool.addClass(className)); } public void emitNEWARRAY(JType elemType) { emitU1(JOpcode.NEWARRAY, elemType.getTag()); } public void emitANEWARRAY(JReferenceType elemType) { emitU2(JOpcode.ANEWARRAY, pool.addDescriptor(elemType)); } public void emitMULTIANEWARRAY(JReferenceType elemType, int dimensions) { setStackProduction(getPC(), -dimensions + 1); emitU2U1(JOpcode.MULTIANEWARRAY, pool.addDescriptor(elemType), dimensions); } public void emitARRAYLENGTH() { emit(JOpcode.ARRAYLENGTH); } // Exception throwing public void emitATHROW() { emit(JOpcode.ATHROW); } // Dynamic typing public void emitCHECKCAST(JReferenceType type) { emitU2(JOpcode.CHECKCAST, pool.addDescriptor(type)); } public void emitINSTANCEOF(JReferenceType type) { emitU2(JOpcode.INSTANCEOF, pool.addDescriptor(type)); } // Monitors public void emitMONITORENTER() { emit(JOpcode.MONITORENTER); } public void emitMONITOREXIT() { emit(JOpcode.MONITOREXIT); } // Wide variants // FIXME setStackProd. will here raise an exception public void emitWIDE(JOpcode opcode, int index) { assert (opcode.code == JOpcode.cILOAD) || (opcode.code == JOpcode.cLLOAD) || (opcode.code == JOpcode.cFLOAD) || (opcode.code == JOpcode.cDLOAD) || (opcode.code == JOpcode.cALOAD) || (opcode.code == JOpcode.cISTORE) || (opcode.code == JOpcode.cLSTORE) || (opcode.code == JOpcode.cFSTORE) || (opcode.code == JOpcode.cDSTORE) || (opcode.code == JOpcode.cASTORE) || (opcode.code == JOpcode.cRET) : "invalide opcode for WIDE: " + opcode; setStackProduction(getPC(), opcode); codeArray.addU1(JOpcode.WIDE.code); codeArray.addU1(opcode.code); codeArray.addU2(index); } public void emitWIDE(JOpcode opcode, int index, int constant) { assert opcode.code == JOpcode.cIINC : "invalid opcode for WIDE: " + opcode; setStackProduction(getPC(), opcode); codeArray.addU1(JOpcode.cWIDE); codeArray.addU1(opcode.code); codeArray.addU2(index); codeArray.addU2(constant); } protected void emitU1(JOpcode opcode, int i1) { setStackProduction(getPC(), opcode); codeArray.addU1(opcode.code); codeArray.addU1(i1); } protected void emitU1U1(JOpcode opcode, int i1, int i2) { setStackProduction(getPC(), opcode); codeArray.addU1(opcode.code); codeArray.addU1(i1); codeArray.addU1(i2); } protected void emitU2(JOpcode opcode, int i1) { setStackProduction(getPC(), opcode); codeArray.addU1(opcode.code); codeArray.addU2(i1); } protected void emitU2U1(JOpcode opcode, int i1, int i2) { setStackProduction(getPC(), opcode); codeArray.addU1(opcode.code); codeArray.addU2(i1); codeArray.addU1(i2); } protected void emitU2U1U1(JOpcode opcode, int i1, int i2, int i3) { setStackProduction(getPC(), opcode); codeArray.addU1(opcode.code); codeArray.addU2(i1); codeArray.addU1(i2); codeArray.addU1(i3); } protected void emitU4(JOpcode opcode, int i1) { setStackProduction(getPC(), opcode); codeArray.addU1(opcode.code); codeArray.addU4(i1); } protected int getU1(int sourcePos) { return codeArray.getU1(sourcePos); } protected int getU2(int sourcePos) { return codeArray.getU2(sourcePos); } protected int getU4(int sourcePos) { return codeArray.getU4(sourcePos); } protected int getS1(int sourcePos) { return codeArray.getS1(sourcePos); } protected int getS2(int sourcePos) { return codeArray.getS2(sourcePos); } protected int getS4(int sourcePos) { return codeArray.getS4(sourcePos); } // Stack size computation ////////////////////////////////////////////////////////////////////// protected int getStackProduction(int pc) { if (stackProduction == null || pc >= stackProduction.length) return UNKNOWN_STACK_SIZE; else return stackProduction[pc]; } protected void setStackProduction(int pc, int production) { if (stackProduction == null) { stackProduction = new int[256]; Arrays.fill(stackProduction, UNKNOWN_STACK_SIZE); } else { while (pc >= stackProduction.length) { int[] newStackProduction = new int[stackProduction.length * 2]; System.arraycopy(stackProduction, 0, newStackProduction, 0, stackProduction.length); Arrays.fill(newStackProduction, stackProduction.length, newStackProduction.length, UNKNOWN_STACK_SIZE); stackProduction = newStackProduction; } } stackProduction[pc] = production; } protected void setStackProduction(int pc, JOpcode opcode) { // TODO we should instead check whether the opcode has known // stack consumption/production. if (getStackProduction(pc) == UNKNOWN_STACK_SIZE) // && opcode.hasKnownProducedDataSize() // && opcode.hasKnownConsumedDataSize()) setStackProduction(pc, opcode.getProducedDataSize() - opcode.getConsumedDataSize()); } protected int computeMaxStackSize() { if (stackSizes == null) { stackSizes = new int[getSize()]; Arrays.fill(stackSizes, UNKNOWN_STACK_SIZE); stackSizes[0] = 0; } int size = computeMaxStackSize(0, 0, 0); // compute stack sizes for exception handlers too ExceptionHandler exh = null; for (Iterator it = exceptionHandlers.iterator(); it.hasNext();) { exh = (ExceptionHandler)it.next(); int exhSize = computeMaxStackSize(exh.getHandlerPC(), 1, 1); if (size < exhSize) size = exhSize; } return size; } protected int computeMaxStackSize(int pc, int stackSize, int maxStackSize) { JCodeIterator iterator = new JCodeIterator(this, pc); for (;;) { int successors = iterator.getSuccessorCount(); if (successors == 0) return maxStackSize; else { assert stackProduction[iterator.getPC()] != UNKNOWN_STACK_SIZE : "unknown stack production, pc=" + iterator.getPC() + " in method " + owner.getName(); stackSize += stackProduction[iterator.getPC()]; if (stackSize > maxStackSize) maxStackSize = stackSize; int nextPC = -1; for (int i = 0; i < successors; ++i) { int succPC = iterator.getSuccessorPC(i); assert succPC >= 0 && succPC < stackSizes.length : iterator.getPC() + ": invalid pc: " + succPC + " op: " + iterator.getOpcode(); if (stackSizes[succPC] == UNKNOWN_STACK_SIZE) { stackSizes[succPC] = stackSize; if (nextPC == -1) nextPC = succPC; else maxStackSize = computeMaxStackSize(succPC, stackSize, maxStackSize); } } if (nextPC == -1) return maxStackSize; else iterator.moveTo(nextPC); } } } // Labels ////////////////////////////////////////////////////////////////////// public static class OffsetTooBigException extends Exception { public OffsetTooBigException() { super(); } public OffsetTooBigException(String message) { super(message); } } protected void checkOffset16(int offset) throws OffsetTooBigException { if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) throw new OffsetTooBigException("offset too big to fit" + " in 16 bits: " + offset); } public class Label { protected boolean anchored = false; protected int targetPC = 0; public void anchorToNext() { assert !anchored; this.targetPC = getPC(); anchored = true; } public int getAnchor() { assert anchored; return targetPC; } protected int getOffset16(int pc, int instrPC) throws OffsetTooBigException { if (anchored) { int offset = targetPC - instrPC; checkOffset16(offset); return offset; } else { recordOffsetToPatch(pc, 16, instrPC, this); return 0; } } protected int getOffset32(int pc, int instrPC) { if (anchored) return targetPC - instrPC; else { recordOffsetToPatch(pc, 32, instrPC, this); return 0; } } } public Label newLabel() { return new Label(); } public Label[] newLabels(int count) { Label[] labels = new Label[count]; for (int i = 0; i < labels.length; ++i) labels[i] = newLabel(); return labels; } protected static class OffsetToPatch { public final int pc; public final int size; public final int instrPC; public final Label label; public OffsetToPatch(int pc, int size, int instrPC, Label label) { this.pc = pc; this.size = size; this.instrPC = instrPC; this.label = label; } } protected void recordOffsetToPatch(int offsetPC, int size, int instrPC, Label label) { offsetToPatch.add(new OffsetToPatch(offsetPC, size, instrPC, label)); } protected void patchAllOffset() throws OffsetTooBigException { Iterator offsetIt = offsetToPatch.iterator(); while (offsetIt.hasNext()) { OffsetToPatch offset = (OffsetToPatch)offsetIt.next(); int offsetValue = offset.label.getAnchor() - offset.instrPC; if (offset.size == 16) { checkOffset16(offsetValue); codeArray.putU2(offset.pc, offsetValue); } else codeArray.putU4(offset.pc, offsetValue); } } // Exception handling ////////////////////////////////////////////////////////////////////// public class ExceptionHandler { protected int startPC, endPC, handlerPC; protected final String catchType; protected final int catchTypeIndex; public void setStartPC(int pc) { this.startPC = pc; } public int getStartPC() { return this.startPC; } public void setEndPC(int pc) { this.endPC = pc; } public int getEndPC() { return this.endPC; } public void setHandlerPC(int pc) { this.handlerPC = pc; } public int getHandlerPC() { return this.handlerPC; } public ExceptionHandler(String catchType) { this(0, 0, 0, catchType); } public ExceptionHandler(int startPC, int endPC, int handlerPC, String catchType) { this.startPC = startPC; this.endPC = endPC; this.handlerPC = handlerPC; this.catchType = catchType; this.catchTypeIndex = (catchType == null ? 0 : pool.addClass(catchType)); } public ExceptionHandler(DataInputStream stream) throws IOException { this.startPC = stream.readShort(); this.endPC = stream.readShort(); this.handlerPC = stream.readShort(); this.catchTypeIndex = stream.readShort(); this.catchType = (catchTypeIndex == 0 ? null : pool.lookupClass(catchTypeIndex)); } public void writeTo(DataOutputStream stream) throws IOException { stream.writeShort(startPC); stream.writeShort(endPC); stream.writeShort(handlerPC); stream.writeShort(catchTypeIndex); } // Follows javap output format for exception handlers. /*@Override*/public String toString() { StringBuffer buf = new StringBuffer(" "); if (startPC < 10) buf.append(" "); buf.append(startPC); buf.append(" "); if (endPC < 10) buf.append(" "); buf.append(endPC); buf.append(" "); buf.append(handlerPC); buf.append(" "); if (catchType != null) { buf.append("Class "); buf.append(catchType); } else buf.append("any"); return buf.toString(); } } public void addExceptionHandler(ExceptionHandler handler) { assert !frozen; exceptionHandlers.add(handler); } public void addExceptionHandler(int startPC, int endPC, int handlerPC, String catchType) { addExceptionHandler(new ExceptionHandler(startPC, endPC, handlerPC, catchType)); } public void addFinallyHandler(int startPC, int endPC, int handlerPC) { assert !frozen; addExceptionHandler(startPC, endPC, handlerPC, null); } public List/*<ExceptionHandler>*/ getExceptionHandlers() { return exceptionHandlers; } // Line numbers ////////////////////////////////////////////////////////////////////// protected int[] lineNumbers = null; protected void ensureLineNumberCapacity(int endPC) { assert !frozen; if (lineNumbers == null) { lineNumbers = new int[endPC]; addAttribute(context.JLineNumberTableAttribute(owner.getOwner(), this)); } else if (lineNumbers.length < endPC) { int[] newLN = new int[Math.max(endPC, lineNumbers.length * 2)]; System.arraycopy(lineNumbers, 0, newLN, 0, lineNumbers.length); lineNumbers = newLN; } } /** * Set all line numbers in the interval [startPC, endPC) to * line, overwriting existing line numbers. */ public void setLineNumber(int startPC, int endPC, int line) { ensureLineNumberCapacity(endPC); Arrays.fill(lineNumbers, startPC, endPC, line); } public void setLineNumber(int instrPC, int line) { setLineNumber(instrPC, instrPC + 1, line); } /** Sets all non-filled line numbers in the interval [startPC, endPC) * to 'line'. */ public void completeLineNumber(int startPC, int endPC, int line) { ensureLineNumberCapacity(endPC); for (int pc = startPC; pc < endPC; ++pc) if (lineNumbers[pc] == 0) lineNumbers[pc] = line; } public int[] getLineNumbers() { assert frozen; if (lineNumbers == null) return new int[0]; else if (lineNumbers.length == getPC()) return lineNumbers; else { int[] trimmedLN = new int[getPC()]; System.arraycopy(lineNumbers, 0, trimmedLN, 0, Math.min(lineNumbers.length, trimmedLN.length)); return trimmedLN; } } // Output ////////////////////////////////////////////////////////////////////// public void writeTo(DataOutputStream stream) throws IOException { assert frozen; stream.writeInt(getSize()); codeArray.writeTo(stream); } // Follows javap output format for opcodes. /*@Override*/ public String toString() { StringBuffer buf = new StringBuffer(); JOpcode opcode = null; int pc = 0, addr = 0; while (pc < codeArray.getSize()) { buf.append("\n "); buf.append(pc); buf.append(":\t"); opcode = JOpcode.OPCODES[codeArray.getU1(pc)]; buf.append(decode(opcode, pc)); if (opcode.code == JOpcode.cTABLESWITCH || opcode.code == JOpcode.cLOOKUPSWITCH) { addr = ((pc / 4 + 1) + 1) * 4; // U4 aligned data int low = codeArray.getU4(addr); int high = codeArray.getU4(addr+4); pc = addr + (2/*low+high*/ + (high - low + 1)/*targets*/) * 4; } else pc += opcode.getSize(); } if (exceptionHandlers.size() > 0) { buf.append("\n Exception table:\n from to target type\n"); Iterator it = exceptionHandlers.iterator(); while (it.hasNext()) { ExceptionHandler exh = (ExceptionHandler)it.next(); buf.append(exh); buf.append("\n"); } } return buf.toString(); } private String decode(JOpcode opcode, int pc) { String ownerClassName = owner.getOwner().getName(); int data, data2; StringBuilder buf = new StringBuilder(); buf.append(opcode.name.toLowerCase()); switch (opcode.code) { case JOpcode.cALOAD: case JOpcode.cASTORE: case JOpcode.cBIPUSH: case JOpcode.cDLOAD: case JOpcode.cDSTORE: case JOpcode.cFLOAD: case JOpcode.cFSTORE: case JOpcode.cILOAD: case JOpcode.cISTORE: case JOpcode.cLLOAD: case JOpcode.cLSTORE: data = codeArray.getU1(pc+1); buf.append("\t"); buf.append(data); break; case JOpcode.cLDC: data = codeArray.getU1(pc+1); buf.append("\t#"); buf.append(data); buf.append("; "); buf.append(pool.lookupEntry(data).toComment(ownerClassName)); break; case JOpcode.cNEWARRAY: data = codeArray.getU1(pc+1); buf.append(" "); buf.append(JType.tagToString(data)); break; case JOpcode.cIINC: data = codeArray.getU1(pc+1); data2 = codeArray.getU1(pc+2); buf.append("\t"); buf.append(data); buf.append(", "); buf.append(data2); break; case JOpcode.cSIPUSH: data = codeArray.getU2(pc+1); buf.append("\t"); buf.append(data); break; case JOpcode.cANEWARRAY: case JOpcode.cCHECKCAST: case JOpcode.cGETFIELD: case JOpcode.cGETSTATIC: case JOpcode.cINSTANCEOF: case JOpcode.cINVOKESPECIAL: case JOpcode.cINVOKESTATIC: case JOpcode.cINVOKEVIRTUAL: case JOpcode.cLDC_W: case JOpcode.cLDC2_W: case JOpcode.cNEW: case JOpcode.cPUTFIELD: case JOpcode.cPUTSTATIC: data = codeArray.getU2(pc+1); buf.append("\t#"); buf.append(data); buf.append("; "); buf.append(pool.lookupEntry(data).toComment(ownerClassName)); break; case JOpcode.cIF_ACMPEQ: case JOpcode.cIF_ACMPNE: case JOpcode.cIFEQ: case JOpcode.cIFGE: case JOpcode.cIFGT: case JOpcode.cIFLE: case JOpcode.cIFLT: case JOpcode.cIFNE: case JOpcode.cIFNONNULL: case JOpcode.cIFNULL: case JOpcode.cIF_ICMPEQ: case JOpcode.cIF_ICMPGE: case JOpcode.cIF_ICMPGT: case JOpcode.cIF_ICMPLE: case JOpcode.cIF_ICMPLT: case JOpcode.cIF_ICMPNE: data = codeArray.getU2(pc+1); // maybe S2 offset buf.append("\t"); buf.append(pc+data); break; case JOpcode.cGOTO: data = codeArray.getS2(pc+1); // always S2 offset buf.append("\t"); buf.append(pc+data); break; case JOpcode.cINVOKEINTERFACE: data = codeArray.getU2(pc+1); data2 = codeArray.getU1(pc+3); buf.append("\t#"); buf.append(data); buf.append(", "); buf.append(data2); buf.append("; "); buf.append(pool.lookupEntry(data).toComment(ownerClassName)); break; case JOpcode.cTABLESWITCH: buf.append("{ //"); int addr = ((pc / 4 + 1) + 1) * 4; // U4 aligned data int low = codeArray.getU4(addr); int high = codeArray.getU4(addr+4); buf.append(low); buf.append(" to "); buf.append(high); for (int i = low; i <= high; ++i) { buf.append("\n\t\t"); buf.append(i); buf.append(": "); buf.append(pc+codeArray.getU4(addr+(i-1)*4)); buf.append(";"); } buf.append("\n\t\tdefault: "); buf.append(pc+codeArray.getU4(addr-4)); buf.append(" }"); default: } return buf.toString(); } } Other Scala examples (source code examples)Here is a short list of links related to this Scala JCode.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.