CompilationUnit

dalvik还是要显得与众不同。

在一个从Java源码编译到JVM字节码的编译器(如javac、ECJ)里,一个“编译单元”(CompilationUnit)指的是一个Java源文件。而在Dalvik VM的JIT里也有一个结构体名为“CompilationUnit”,这个千万不能跟Java源码级的编译单元弄混了——它在这里指的就是一个“trace”。

http://hllvm.group.iteye.com/group/topic/17798

万能的WIKI是这么说的:

http://en.wikipedia.org/wiki/Single_Compilation_Unit

看起来WIKI的解释和java JVM的定义差不多。

在源代码里,它是这么定义的:


typedef struct CompilationUnit {
    int numInsts;
    int numBlocks;
    GrowableList blockList;
    const Method *method;
#ifdef ARCH_IA32
    int exceptionBlockId;               // the block corresponding to exception handling
#endif
    const JitTraceDescription *traceDesc;
    LIR *firstLIRInsn;
    LIR *lastLIRInsn;
    LIR *literalList;                   // Constants
    LIR *classPointerList;              // Relocatable
    int numClassPointers;
    LIR *chainCellOffsetLIR;
    GrowableList pcReconstructionList;
    int headerSize;                     // bytes before the first code ptr
    int dataOffset;                     // starting offset of literal pool
    int totalSize;                      // header + code size
    AssemblerStatus assemblerStatus;    // Success or fix and retry
    int assemblerRetries;               // How many times tried to fix assembly
    unsigned char *codeBuffer;
    void *baseAddr;
    bool printMe;
    bool allSingleStep;
    bool hasClassLiterals;              // Contains class ptrs used as literals
    bool hasLoop;                       // Contains a loop
    bool hasInvoke;                     // Contains an invoke instruction
    bool heapMemOp;                     // Mark mem ops for self verification
    bool usesLinkRegister;              // For self-verification only
    int profileCodeSize;                // Size of the profile prefix in bytes
    int numChainingCells[kChainingCellGap];
    LIR *firstChainingLIR[kChainingCellGap];
    LIR *chainingCellBottom;
    struct RegisterPool *regPool;
    int optRound;                       // round number to tell an LIR's age
    jmp_buf *bailPtr;
    JitInstructionSetType instructionSet;
    /* Number of total regs used in the whole cUnit after SSA transformation */
    int numSSARegs;
    /* Map SSA reg i to the Dalvik[15..0]/Sub[31..16] pair. */
    GrowableList *ssaToDalvikMap;

    /* The following are new data structures to support SSA representations */
    /* Map original Dalvik reg i to the SSA[15..0]/Sub[31..16] pair */
    int *dalvikToSSAMap;                // length == method->registersSize
    BitVector *isConstantV;             // length == numSSAReg
    int *constantValues;                // length == numSSAReg

    /* Data structure for loop analysis and optimizations */
    struct LoopAnalysis *loopAnalysis;

    /* Map SSA names to location */
    RegLocation *regLocation;
    int sequenceNumber;

    /*
     * Set to the Dalvik PC of the switch instruction if it has more than
     * MAX_CHAINED_SWITCH_CASES cases.
     */
    const u2 *switchOverflowPad;

    JitMode jitMode;
    int numReachableBlocks;
    int numDalvikRegisters;             // method->registersSize + inlined
    BasicBlock *entryBlock;
    BasicBlock *exitBlock;
    BasicBlock *puntBlock;              // punting to interp for exceptions
    BasicBlock *backChainBlock;         // for loop-trace
    BasicBlock *curBlock;
    BasicBlock *nextCodegenBlock;       // for extended trace codegen
    GrowableList dfsOrder;
    GrowableList domPostOrderTraversal;
    BitVector *tryBlockAddr;
    BitVector **defBlockMatrix;         // numDalvikRegister x numBlocks
    BitVector *tempBlockV;
    BitVector *tempDalvikRegisterV;
    BitVector *tempSSARegisterV;        // numSSARegs
    bool printSSANames;
    void *blockLabelList;
    bool quitLoopMode;                  // cold path/complex bytecode
} CompilationUnit;
不得不说,这个数据结构实在是太大了,这样真的好维护吗?


但对于程序来说,它复杂度和它重要性一般是成正比的。

CU是一个贯穿整个程序的结构体,一个trace包含的几乎所有信息,都被CU整合了在一次,这也是因此为何CU如此复杂和臃肿的原因。

你若想了解一个软件的执行思路,必须的吃透它最主要的数据结构,以及它的组织方式。因为数据结构的组织方式,决定了软件该如何处理它。例如,使用了大量指针的数据结构,很明显是必须要使用动态链表来保存数据的。而之所以使用了大量的动态链表,是因为数据结构要描述的对象大小的不确定性。例如对于dalvik来说,trace的长度不一定,你不能假定它是64K或者是128K。静态减少了复杂度,但是对于不规则的对象却无法处理;动态引入了弹性,但是必然会引入复杂度。

从结构体开头就可以看到,”const Method *method;“。这是一个指针,那么对于一个CU来说,是必须要对应一个method,但是一个method可能包含了几个CU.

比较重要的还有,这是整个CU的入口,出口对应的LIR:

    LIR *firstLIRInsn;
    LIR *lastLIRInsn;
    LIR *literalList;                   // Constants
    LIR *classPointerList;              // Relocatable

当CU被编译成为LIR的时候,LIR是保存成为链表形式的。

除此之外,CU还会包含大量的BB,整个CU的入口,出口等。

    BasicBlock *entryBlock;
    BasicBlock *exitBlock;
    BasicBlock *puntBlock;              // punting to interp for exceptions
    BasicBlock *backChainBlock;         // for loop-trace
    BasicBlock *curBlock;
    BasicBlock *nextCodegenBlock;       // for extended trace codegen

之前所说过,BB是只有一个IN/OUT的branch,它自然也包含了MIR。因此,BB,MIR,LIR在CU这里,一家都齐全了。


你可能感兴趣的:(CompilationUnit)