jitir.c

来自「This is a resource based on j2me embedde」· C语言 代码 · 共 2,041 行 · 第 1/5 页

C
2,041
字号
/* * @(#)jitir.c	1.316 06/10/25 * * Copyright  1990-2008 Sun Microsystems, Inc. All Rights Reserved.   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER   *    * This program is free software; you can redistribute it and/or   * modify it under the terms of the GNU General Public License version   * 2 only, as published by the Free Software Foundation.    *    * This program is distributed in the hope that it will be useful, but   * WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   * General Public License version 2 for more details (a copy is   * included at /legal/license.txt).    *    * You should have received a copy of the GNU General Public License   * version 2 along with this work; if not, write to the Free Software   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA   * 02110-1301 USA    *    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa   * Clara, CA 95054 or visit www.sun.com if you need additional   * information or have any questions.  * */#include "javavm/include/defs.h"#include "javavm/include/objects.h"#include "javavm/include/classes.h"#include "javavm/include/utils.h"#include "javavm/include/bcutils.h"#include "javavm/include/typeid.h"#include "javavm/include/bcattr.h"#include "javavm/include/interpreter.h"#include "javavm/include/indirectmem.h"#include "javavm/include/clib.h"#include "javavm/include/opcodes.h"#include "javavm/include/porting/doubleword.h"#include "javavm/include/porting/int.h"#include "javavm/include/porting/jit/jit.h"#include "javavm/include/jit/jit.h"#include "javavm/include/jit/jitir.h"#include "javavm/include/jit/jitcontext.h"#include "javavm/include/jit/jitirdump.h"#include "javavm/include/jit/jitopt.h"#include "javavm/include/jit/jitutils.h"#include "javavm/include/jit/jitirnode.h"#include "javavm/include/jit/jitirlist.h"#include "javavm/include/jit/jitirrange.h"#include "javavm/include/jit/jitirblock.h"#include "javavm/include/jit/jitintrinsic.h"#include "javavm/include/jit/jitmemory.h"#include "javavm/include/jit/jitstats.h"#include "javavm/include/jit/jitdebug.h"#include "javavm/include/jit/jitasmconstants.h"#ifdef CVM_HW#include "include/hw.h"#endif/*#define CVM_DEBUG_RUNTIME_CHECK_ELIMINATION*//*#define LOCALREF_INFO_REFINEMENT_DEBUGGING*//* NOTES on:   The Compilation Context and Method Contexts   ===========================================   When a method is being compiled, we shall call this the root method.  There   is only one Compilation Context per compilation pass i.e. per root method.   However, during the compilation of that method, we may inline other methods   that it calls.  For each of these inlined methods, a Method Context will be   assigned.   The Compilation Context contains a Method Contexts stack.  Each time a   method is inlined, a Method Context is pushed onto that stack.  When we are   done inlining that method, its Method Context will be popped.   The root method also has a Method Context.  It is easy to think of Method   Contexts as being equivalent to stack frames on the the runtime Java stack   since it sort of keeps track of which method is being "translated".   However, this is not entirely true.  Unlike stack frames, the Method Context   is not popped off when we reach a return opcode.  Instead, it is popped of   when we are done processing the inlined method.  This is because we need to   translate the entire method, and the return opcode is not guaranteed to be   the last opcode we will encounter for that method.   All blocks of an inlined method or root method are translated using the   same Method Context.  But each Method Context has a locals[] array, and it   is re-initialized every time we start up the translation of another block.   Root Nodes and the CVMJITirDoSideEffectOperator()   =================================================   Every time a root node is to be added, we must make sre that the   CVMJITirDoSideEffectOperator() has been called at an appropriate prior time   to ensure that evaluation order of operands on the stack are preserved.   There is an assertion in the root node constructor CVMJITirnodeNewRoot()   that will ensure that all items on the operand stack has been evaluated   before the root node is inserted.*/typedef CVMJITInlinePreScanInfo Inlinability;#define CVMJITlocalStateMarkPC(con, mc, localNo, pc) {        \    CVMassert((localNo) < (mc)->localsSize);                  \    CVMassert((mc)->localsState != NULL);                     \    {                                                         \	if ((mc)->localsState[(localNo)] == 0) {              \            (mc)->localsState[(localNo)] = (pc);              \        } else if ((mc)->localsState[(localNo)] != (pc)) {    \            CVMJITerror(con, CANNOT_COMPILE,                  \	        "This local is already used by anther JSR");  \	}                                                     \    }                                                         \}#define CVMJITlocalStateGetPC(mc, localNo)                \    (CVMassert((mc)->localsState[(localNo)] != 0),        \     ((mc)->localsState[(localNo)]))#undef getLocalNo#define  getLocalNo(node) \    (CVMJITirnodeGetLocal(CVMJITirnodeValueOf(node))->localNo)static CVMJITIRNode*arrayLengthCacheGet(CVMJITCompilationContext* con, CVMJITIRNode* objRef);static voidarrayLengthCachePut(CVMJITCompilationContext* con, CVMJITIRNode* arrayrefNode,                    CVMJITIRNode* arrayLengthNode);static voidarrayLengthCacheKillForLocal(CVMJITCompilationContext* con, CVMUint32 localNo);static CVMJITMethodContext*pushMethodContext(CVMJITCompilationContext* con, 		  CVMMethodBlock* mb,		  Inlinability inlineStatus,		  CVMBool doNullCheck);static voidspliceContextBlocks(CVMJITCompilationContext* con,    CVMJITMethodContext *mc, CVMMethodBlock *targetMb,    CVMBool doNullCheck);static CVMBooltranslateInlinePrologue(CVMJITCompilationContext* con,    CVMJITIRBlock* currBlock,    CVMJITIRBlock* collBlock);static CVMBool translateOutOfLineInvoke(CVMJITCompilationContext* con,    CVMJITIRBlock* invBlock);static voidrefineLocalsInfo(CVMJITCompilationContext* con);#ifdef CVM_JIT_REGISTER_LOCALS/* Returns true if the block has seen an ASSIGN node for the local */static CVMBoolassignNodeExists(CVMJITIRNode** assignNodes, CVMUint16 assignNodesCount,		 CVMUint16 localNo);/* Add target block to list of blocks we flow incoming locals from */static voidaddIncomingLocalsSuccessorBlock(CVMJITCompilationContext* con,				CVMJITIRBlock* curbk,				CVMJITIRBlock* successorBk,				CVMBool fallthrough);#endifstatic CVMJITIRBlock**CVMJITirblockMapCreate(CVMJITCompilationContext *con, CVMMethodBlock *mb){    /* Allocate an extra slot at the end for a "return" block if needed */    return (CVMJITIRBlock**)CVMJITmemNew(con,	JIT_ALLOC_IRGEN_OTHER,	(CVMmbCodeLength(mb) + 1) * sizeof(CVMJITIRBlock*));}/* * Java treats byte, boolean, char, and shorts as int, so we fold all * of these types into the type int. Basically we fold into the known * set of "computational types" as the VM Spec likes to call them. */static CVMUint8CVMJITfoldType(CVMUint8 typeTag){    switch (typeTag) {    case CVM_TYPEID_BYTE:    case CVM_TYPEID_BOOLEAN:    case CVM_TYPEID_CHAR:    case CVM_TYPEID_SHORT:	return CVM_TYPEID_INT;    default:	return typeTag;    }}static voidnullCheckMark(CVMJITCompilationContext* con, CVMJITIRNode* node);static CVMBoolnullCheckEmitted(CVMJITCompilationContext* con, CVMJITIRNode* node);static CVMBoolnullCheckNeeded(CVMJITCompilationContext* con, CVMJITIRNode* node);/* * Kill all cached field and array reads, and any derived pointers */static voidkillAllCachedReferences(CVMJITCompilationContext* con);static CVMJITIRNode *monitorEnter(CVMJITCompilationContext* con,	     CVMJITIRBlock* curbk,	     CVMJITIRNode *node){    /* Synchronization points invalidate cached field results */    killAllCachedReferences(con);        /* monitorenter inserts a root node.  So we must call the       CVMJITirDoSideEffectOperator() to preserve eval order of       operands on the stack: */    CVMJITirDoSideEffectOperator(con, curbk);    node = CVMJITirnodeNewUnaryOp(con, CVMJIT_ENCODE_MONITOR_ENTER,				  node);     CVMJITirnodeSetThrowsExceptions(node);    return node;}static CVMJITIRNode *monitorExit(CVMJITCompilationContext* con,	    CVMJITIRBlock* curbk,	    CVMJITIRNode *node){    /* Synchronization points invalidate cached field results */    killAllCachedReferences(con);        /* monitorexit inserts a root node.  So we must call the       CVMJITirDoSideEffectOperator() to preserve eval order of       operands on the stack: */    CVMJITirDoSideEffectOperator(con, curbk);    node = CVMJITirnodeNewUnaryOp(con, CVMJIT_ENCODE_MONITOR_EXIT,				  node);     CVMJITirnodeSetThrowsExceptions(node);    return node;}/* * Create a new root node that marks the beginning of an inlined method */static voidbeginInlining(CVMJITCompilationContext* con, CVMJITIRBlock* curbk,	      CVMUint16 tag, CVMJITMethodContext* mc){    CVMJITIRNode* mcConst = CVMJITirnodeNewConstantMC(con, mc);    CVMJITIRNode* info;    info = CVMJITirnodeNewUnaryOp(con, tag, mcConst);    CVMJITirnodeSetHasUndefinedSideEffect(info);    CVMJITirnodeNewRoot(con, curbk, info);}/*  * Create a node that marks the end of an inlined method.  */static CVMJITIRNode*endInlining(CVMJITCompilationContext* con, CVMJITIRBlock* curbk,	    CVMJITIRNode* arg){    /* Another inlining performed */    con->numInliningInfoEntries++;    if (arg == NULL) {	CVMJITIRRoot *prevRoot = 	    (CVMJITIRRoot*)CVMJITirlistGetTail(CVMJITirblockGetRootList(curbk));	CVMJITIRNode* prevExpr = (prevRoot == NULL) ? NULL :	    CVMJITirnodeGetRootOperand(prevRoot);	if (prevExpr != NULL && CVMJITirnodeIsEndInlining(prevExpr)) {	    ++CVMJITirnodeGetNull(prevExpr)->data;	} else {	    CVMJITIRNode *eiNode =		CVMJITirnodeNewNull(con, CVMJIT_ENCODE_END_INLINING_LEAF);	    CVMJITirnodeGetNull(eiNode)->data = 1;	    CVMJITirnodeNewRoot(con, curbk, eiNode);	}	return NULL;    } else {	CVMUint16 tid = CVMJITgetTypeTag(arg);	CVMJITIRNode *eiNode =	    CVMJITirnodeNewNull(con, CVMJIT_ENCODE_END_INLINING_LEAF);	CVMJITirnodeGetNull(eiNode)->data = 1;	eiNode = CVMJITirnodeNewBinaryOp(con, CVMJIT_ENCODE_SEQUENCE_L(tid),	    arg, eiNode);	CVMJITirnodeSetHasUndefinedSideEffect(eiNode);	return eiNode;    }}/* Purpose: Compute the number of operands on the operands stack that the            specified argSize correlates to starting from the current top of            the operand stack. */static CVMUint32argSize2argCount(CVMJITCompilationContext *con, CVMUint16 argSize){    CVMJITStack *operandStack = con->operandStack;    CVMUint32 currentIndex = CVMJITstackCnt(con, con->operandStack) - 1;    CVMUint32 argCount;    /* Compute the starting stack index (exclude args): */    while (argSize > 0) {        CVMJITIRNode *node;        node = CVMJITstackGetElementAtIdx(con, operandStack, currentIndex);        currentIndex--;        if (CVMJITirnodeIsDoubleWordType(node)) {            argSize -= 2;        } else {            argSize --;        }    }    argCount = CVMJITstackCnt(con, con->operandStack) - (currentIndex + 1);    return argCount;}/* * Evaluate a stack item and bump refcount. */voidCVMJITirForceEvaluation(CVMJITCompilationContext* con, CVMJITIRBlock* curbk,			CVMJITIRNode* node){    /*     * If the node has already been evaluated, there's no point in forcing     * evaluation of it.  A node can only be evaluated once though its     * result may be used many times.     * CONSTANT nodes are automatically considered to be     * already evaluated by definition.     */    if (!CVMJITirnodeHasBeenEvaluated(node)) {	CVMJITirnodeNewRoot(con, curbk, node);	/* From this point, this tree has been evaluated: */        CVMJITstatsRecordInc(con, CVMJIT_STATS_NUMBER_OF_TEMP_NODES);    }}#ifdef CVM_JIT_REGISTER_LOCALS/* * Add this local to our list of incoming locals if there is room * and we are still allowing more items to be added to the list. We * stop adding if we know the incoming local will be trashed * before referenced (like if a method call is made). */static voidaddIncomingLocal(CVMJITCompilationContext* con, CVMJITIRBlock* bk,		 CVMJITIRNode* localNode){    CVMUint16 typeTag = CVMJITgetTypeTag(localNode);    /*     * Check all the conditions for which we will not allow the     * local to be added.     */    if (	/* allow longs only if they fit in one register */#if (CVMCPU_MAX_REG_SIZE == 1)	!(typeTag == CVM_TYPEID_LONG) &&#endif	/* allow doubles only if they fit in one register */#if !defined(CVM_JIT_USE_FP_HARDWARE) || (CVMCPU_FP_MAX_REG_SIZE == 1)	!(typeTag == CVM_TYPEID_DOUBLE) &&#endif	!(typeTag == CVM_TYPEID_OBJ && bk->noMoreIncomingRefLocals) &&	!bk->noMoreIncomingLocals && 	bk->incomingLocalsCount < CVMJIT_MAX_INCOMING_LOCALS)    {	int i;	CVMUint16 localNo = getLocalNo(localNode);	/* don't add the same local twice */	for (i = 0; i < bk->incomingLocalsCount; i++) {	    if (bk->incomingLocals[i] != NULL) {		if (getLocalNo(bk->incomingLocals[i]) == localNo) {		    return;  /* local already been added */		}	    }	}	/* don't add locals for which there is an ASSIGN node already */	if (assignNodeExists(con->assignNodes,			     con->assignNodesCount, localNo)) {	    return;	}	bk->incomingLocals[bk->incomingLocalsCount] = localNode;	bk->incomingLocalsCount++;    }}#endif /* CVM_JIT_REGISTER_LOCALS *//* * Handle local access. If we are in the process of inlining, go through * the "method context". If not, create a new LOCAL node and push it on the * stack. */static CVMJITIRNode*getLocal(CVMJITCompilationContext* con,	 CVMJITMethodContext* mc, CVMUint16 localNo, CVMUint16 typeTag) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?