📄 codeblock.java
字号:
/** * Abstract class to support building code on-the-fly * @version $Id: CodeBlock.java,v 1.12 1999/03/09 01:57:29 pab Exp $ * @author Peter A. Bigot * * This class is used by the Toba just-in-time compiler to support code * generation when classes are loaded. It extends the classfile * MethodCode class, which has basic information about the method and code * type. It is itself abstract, and is extended by machine-specific * classes which build the code appropriate for the target machine. * Essentially, code is built up instruction-by-instruction until * complete. It is then transferred to a native block of memory. * Procedure calls are handled separately, since they will generally need * to be backpatched once the native block for the target function is * known. *//* This is part of the Just-In-Time component of the Toba system */package toba.jit;import toba.classfile.*;import toba.runtime.*;abstract classCodeBlock extends MethodCode{ /* We could use a Vector object for this, but hand-managing does * just as well, and may allow some tricks that Vector doesn't. */ private byte codeBytes[]; // This is where instructions are built up private int maxCodeBytes = 0; // Maximum length of Java array private int numCodeBytes = 0; // Current length of Java array protected int instrToByteOffs []; // Mapping from instr index to code start protected int nBackPatches; // Number of backpatches in this code so far protected long handlerTableAddress; // Where in memory handler table lives protected int localHandlerTarget; // Where relative to mtentry local handler target is protected BackpatchInfo syncwrap_bpi; // Backpatch info for wrapped sync method protected CodeGen myGenerator; // Who did the generation of this code? protected ClassLoader codeClassLoader; // Who loaded this code? public void setCodeClassLoader (ClassLoader cl) { codeClassLoader = cl; return; } public ClassLoader getCodeClassLoader () { return codeClassLoader; } /* Set this true if byte order is LSB to MSB (Intel, Vax), and false * if byte order is MSB to LSB (SPARC). */ protected boolean littleEndian = false; /* If true, jumps are relative to the pc of the following instruction; * otherwise, they are relative to the pc of the jump/call instruction. */ protected boolean jumpFromNextInstr = false; /* If we don't make this static, we have to qualify every call to BV, * which is a royal pain. Let's just pretend we'll never generate * code for two different architectures at the same time. */ private static int valBVrlen = 32; // Default expected length of incoming string bitvecs /* Set this true if we want storeWord to verify that it's storing * into an aligned area. Necessary on SPARC, undesirable on Intel. */ private boolean checkWordAlign = true; /* Set this to true if we don't want to store data into the codeByte * array, even if we haven't locked it yet. */ private boolean lockCodeBytes = false; private boolean allNativeCode = false; public void setAllNativeCode (boolean bv) { allNativeCode = bv; return; } /** Create a new CodeBlock object * @param m method to which code block applies * @param imax number of bytes expected in code block */ public CodeBlock (Method m, // Method the code applies to int imax) // Expected size of code block { super (m); /* Allocate a new array, and set the current size to 0, and the * max size to that provided */ codeBytes = new byte [imax]; maxCodeBytes = imax; numCodeBytes = 0; /* Allocate space for a mapping from instruction index to where * code related to that instruction starts. */ if (null == m) { instrToByteOffs = new int [10]; } else { if (null == m.instrs) { instrToByteOffs = new int [10]; } else { instrToByteOffs = new int [m.instrs.length]; } } nBackPatches = 0; localHandlerTarget = -1; handlerTableAddress = 0L; } /** Create a new CodeBlock object * @param m method to which code block applies */ public CodeBlock (Method m) { this (m, 10); } /** Set boolean indicating whether endianness for storing word data * is little-endian. * @param nv new value for littleEndian * @returns boolean previous value of littleEndian */ protected boolean setLittleEndian (boolean nv) { boolean ov = littleEndian; littleEndian = nv; return ov; } /** Set boolean indicating whether relative jumps are from this instruction * (false) or the next one (true). * @param nv new value for jumpFromNextInstr * @returns boolean previous value of jumpFromNextInstr */ protected boolean setJumpFromNextInstr (boolean nv) { boolean ov = jumpFromNextInstr; jumpFromNextInstr = nv; return ov; } protected boolean setCheckWordAlign (boolean nv) { boolean ov = checkWordAlign; checkWordAlign = nv; return ov; } protected boolean setLockCodeBytes (boolean nv) { boolean ov = lockCodeBytes; lockCodeBytes = nv; return ov; } /** Convert from a signed integer to an nbit-bit string encoding * @param bv integer representation of value to encode * @param nbits number of bits used in encoding * @returns nbit-character string of 0s and 1s encoding bv */ protected static String BS (int bv, // Value to encode int nbits) // Number of bits to use { String sreg = ""; // Built-up bit string /* Build up the string in MSB to LSB order left to right */ for (int bi = nbits-1; 0 <= bi; bi--) { sreg += (0 != (bv & (1 << bi))) ? "1" : "0"; } return sreg; } /** Convert from a bit string to an int * @param bs A string of 0s and 1s; spaces are ignored * @param rlen String must have rlen 0s + 1s * @returns the integer value represented by the string */ protected static int BV (String bs, // Bit string to decode int rlen) // Required length of string in bits { int val; // Value being built up int bm; // Bit mask of next bit in buildup int nbits; // Number of valid bits in the string int i; // Index over bits in string // System.out.println ("Converting " + bs + " to " + rlen + "-bit integer"); /* Walk from LSB to MSB building up the value. */ val = 0; bm = 1; nbits = 0; for (i = bs.length() - 1; 0 <= i; i--) { char c; c = bs.charAt (i); if (' ' == c) { continue; } if ('1' == c) { val |= bm; } else if ('0' != c) { throw new InternalError ("CodeBlock.BV: Input bit string has illegal character: " + bs); } ++nbits; bm <<= 1; } if (rlen != nbits) { throw new InternalError ("CodeBlock.BV: Input bit string has " + nbits + " valid bit characters; need " + rlen); } return val; } /** Convert from a bit string to an int, using the default length. * @param bs A string of 0s and 1s; spaces are ignored * @returns the integer value represented by the string */ protected static int BV (String bs) // Bit string to decode { return BV (bs, valBVrlen); } /** Set the default expected length for bitstrings decoded by BV * @param nlen new length for default BV rlen * @returns int previous value of default BV rlen */ protected int setBVlength (int nlen) { int olen; olen = valBVrlen; valBVrlen = nlen; return olen; } /** What will be the offset, in bytes, of the next instruction? * @returns index used for next instruction */ public int nextByteOffs () { return numCodeBytes; } public void setByteOffs (int ncb) { if (ncb > numCodeBytes) { throw new InternalError ("CodeBlock: attempt to jump to offset " + ncb + " with only " + numCodeBytes + " available."); } numCodeBytes = ncb; return; } private int epilogOffs; /** Indicate that from here on out is epilog code */ public void setEpilogOffs () { epilogOffs = numCodeBytes; } /** Return the marked offset in the codeBytes of the function epilog */ public int getEpilogOffs () { return epilogOffs; } /** Okay, so what's all this native block stuff? * We're building machine code that is to be executed directly. To * invoke that code, we need a function pointer to it. That has to be * the start of a sequence of bytes in C space. Java array data won't * do, since it can be garbage collected or moved arbitrarily. * * Now, subroutine calls require the address of the subroutine being * called (whattaconcept), but we may not have built the code for that * routine yet. Since we can't allocate the C space until we know how * long the function will be, we have to save the location of unresolved * calls for future backpatching. So, after we've built the function * code, leaving holes for to-be-resolved calls, we allocate the C block * where the function will live. We can then use that address to * back-patch calls, even if the code hasn't been stored into it yet * (e.g., if there are calls to be backpatched in this function). * A further complication, even if we know the address of a routine * we're going to call, is on architectures like the SPARC where calls * are relative to the address of the call instruction. * So, basically, we can build code during the load phase, but can't * install the call instructions until linking, when all modules already * have code blocks allocated. * * Does that make sense to everybody? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -