📄 jitregman.c
字号:
/* * @(#)jitregman.c 1.167 06/10/10 * * 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. * *//* * Register manager implementation. */#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/ccee.h"#include "javavm/include/globals.h"#include "javavm/include/jit/jit.h"#include "javavm/include/jit/jitir.h"#include "javavm/include/jit/jitcontext.h"#include "javavm/include/jit/jitcodebuffer.h"#include "javavm/include/jit/jitirnode.h"#include "javavm/include/jit/jitirblock.h"#include "javavm/include/jit/jitcomments.h"#include "javavm/include/jit/jitmemory.h"#include "javavm/include/jit/jitirdump.h"#include "javavm/include/jit/jitstackmap.h"#include "portlibs/jit/risc/include/porting/jitriscemitter.h"#include "portlibs/jit/risc/include/export/jitregman.h"#include "portlibs/jit/risc/jitopcodes.h"#include "portlibs/jit/risc/jitstackman.h"#include "portlibs/jit/risc/jitgrammar.h"#include "javavm/include/clib.h"#ifdef CVM_DEBUG_ASSERTS#define CVMJIT_STRICT_REFLOCAL_ASSERTS#endif#define RM_INITIAL_REF_COUNT_SIZE 64 /* more than ever needed */#define RM_STICKY_REF_COUNT 255#ifdef CVM_JIT_USE_FP_HARDWARE#define RM_MAX_INTERESTING_REG (con)->maxInteresting#define RM_MIN_INTERESTING_REG (con)->minInteresting#define RM_SAFE_SET (con)->safeSet#define RM_UNSAFE_SET (con)->unsafeSet#define RM_ANY_SET (con)->anySet#define RM_SINGLE_REG_ALIGN (con)->singleRegAlignment#define RM_DOUBLE_REG_ALIGN (con)->doubleRegAlignment#define RM_MOV_OPCODE(_con) (_con)->movOpcode#define RM_MAX_REG_SIZE(_con) (_con)->maxRegSize#else /* not using FP hardware */#define RM_MAX_INTERESTING_REG CVMCPU_MAX_INTERESTING_REG#define RM_MIN_INTERESTING_REG CVMCPU_MIN_INTERESTING_REG#define RM_SAFE_SET CVMRM_SAFE_SET#define RM_UNSAFE_SET CVMRM_UNSAFE_SET#define RM_ANY_SET CVMRM_ANY_SET#define RM_SINGLE_REG_ALIGN CVMCPU_SINGLE_REG_ALIGNMENT#define RM_DOUBLE_REG_ALIGN CVMCPU_DOUBLE_REG_ALIGNMENT#define RM_MAX_REG_SIZE(_con) CVMCPU_MAX_REG_SIZE#define RM_MOV_OPCODE(_con) CVMCPU_MOV_OPCODE#endif#define RM_STORE_OPCODE(_con,_size) ((_con)->storeOpcode[(_size)-1])#define RM_LOAD_OPCODE(_con,_size) ((_con)->loadOpcode[(_size)-1])#if ((CVMCPU_MAX_REG_SIZE != 1) || \ (defined(CVM_JIT_USE_FP_HARDWARE) && (CVMCPU_FP_MAX_REG_SIZE != 1)))/* there are some double-word registers */#define RM_NREGISTERS(_con,_size) ((_size) <= RM_MAX_REG_SIZE(_con) ? 1 : 2)#else/* all the registers are single-word */#define RM_NREGISTERS(_con,_size) (_size)#endif#ifdef CVM_DEBUG_ASSERTS#define RM_INT_KEY 1#define RM_FP_KEY 2#define CVMRMassertContextMatch(cx,rp) CVMassert((cx)->key == (rp)->key)#else#define CVMRMassertContextMatch(cx,rp)#endiftypedef enum { CVMRM_REGPREF_TARGET, CVMRM_REGPREF_SCRATCH, CVMRM_REGPREF_PERSISTENT} CVMRMRegisterPreference;#define DEFAULT_CONSTANT_PREF CVMRM_REGPREF_PERSISTENT#define DEFAULT_LOCAL_PREF CVMRM_REGPREF_PERSISTENT#define DEFAULT_RESOURCE_PREF CVMRM_REGPREF_PERSISTENTstatic voidCVMRMpinResource0(CVMJITRMContext*, CVMRMResource*, CVMRMregset target, CVMRMregset avoid, CVMRMRegisterPreference pref, CVMBool strict);#ifdef CVM_JIT_REGISTER_LOCALSstatic voidCVMRMbindAllIncomingLocalNodes(CVMJITCompilationContext* con, CVMJITIRBlock* b);#endifstatic voidCVMRMbindAllUsedNodes(CVMJITCompilationContext* con, CVMJITIRBlock* b);static voidCVMRMbindUseToResource(CVMJITCompilationContext* con, CVMJITIRNode* expr);/* Purpose: Gets an available reg from the specified register set. */static intfindMaxRegInSet( CVMRMregset target, int minInteresting, int maxInteresting, int alignment){#ifndef IAI_ROUNDROBIN_REGISTER_ALLOCATION int i; /* The register with the highest ID value in the specified set will be selected first: */ if (alignment == 2 ) maxInteresting &= ~1; /* round down to even */ for (i=maxInteresting; i>=minInteresting; i-= alignment ) { if ((target & (1U<<i)) != 0) return i; } return -1;#else /* !IAI_ROUNDROBIN_REGISTER_ALLOCATION */ /* * Keep track of last register allocated so next time we can start * with the register that follows it. */ static int round = RM_MAX_INTERESTING_REG; int i; if (alignment == 2 ) { maxInteresting &= ~1; /* round down to even */ minInteresting = (minInteresting + 1) & ~1; /* round up to even */ } if (round < minInteresting || round > maxInteresting) { round = maxInteresting; } if (alignment == 2 ) { round &= ~1; /* round down to even */ } /* Seach the round to find appropriate register. Seach from the round down to min */ for (i = round; i >= minInteresting; i -= alignment) { if ((target & (1U<<i)) != 0) { round = i -1; return i; } } /* Search from max down to round */ for (i = maxInteresting; i > round; i -= alignment) { if ((target & (1U<<i)) != 0) { round = i -1; return i; } } return -1;#endif /* !IAI_ROUNDROBIN_REGISTER_ALLOCATION */}/* Purpose: Gets an available reg from the specified register set. */static intfindMinRegInSet( CVMRMregset target, int minInteresting, int maxInteresting, int alignment, int nregs){ int i; /* * Make search easier if a 32-bit pair is needed by masking off the upper * register of each pair if the lower register is not available. * This way we know if any bit is set, then the following bit is also set. */ if (nregs > 1) { target = target & (target >> 1); } /* If alignment is required, then make sure we start on an aligned reg */ CVMassert(alignment > 0); if (alignment != 1) { int left = (minInteresting % alignment); if (left > 0) { /* round up to alignment */ minInteresting += alignment - left; } } CVMassert(minInteresting % alignment == 0); /* Now we are all set to grab the first available register. */ for (i=minInteresting; i<=maxInteresting; i+= alignment ) { if ((target & (1U<<i)) != 0) return i; } return -1;}/* * Spill Location Management. Finding and relinquishing spill locations * using CVMJITSet structures */static voidresizeSpillRefCount(CVMJITCompilationContext* con, int needed){ int newsize = needed; CVMUint8* newallocation; /* round up to multiple of 64 */ newsize = (newsize+63) & ~63; CVMassert(newsize > con->RMcommonContext.spillBusyRefSize); newallocation = CVMJITmemNew(con, JIT_ALLOC_CGEN_REGMAN, newsize*sizeof(CVMUint8)); memcpy(newallocation, con->RMcommonContext.spillBusyRefCount, con->RMcommonContext.spillBusyRefSize*sizeof(CVMUint8)); con->RMcommonContext.spillBusyRefCount = newallocation; con->RMcommonContext.spillBusyRefSize = newsize;}static voidresetSpillMap(CVMJITCompilationContext* con, CVMJITIRBlock* b){ CVMJITRMCommonContext* common = &(con->RMcommonContext); /* reset the spill set */ CVMJITsetClear(con, &(common->spillBusySet)); memset(common->spillBusyRefCount, 0, common->spillBusyRefSize * sizeof(CVMUint8)); /* mark all phiWords as busy */ if (con->maxPhiSize > 0){ int i; int maxPhi = con->maxPhiSize; CVMUint8* refElement; CVMJITsetPopulate(con, &(common->spillBusySet), maxPhi); if (maxPhi > common->spillBusyRefSize){ resizeSpillRefCount(con, maxPhi); } refElement = common->spillBusyRefCount; for( i = 0; i < maxPhi; i++){ *(refElement++) = RM_STICKY_REF_COUNT; } } /* initialize the spill ref set */ CVMJITsetClear(con, &(con->RMcommonContext.spillRefSet)); con->RMcommonContext.maxPhiSize = con->maxPhiSize; con->RMcommonContext.maxSpillNumber = con->maxPhiSize-1;}static intfindSpillLoc( CVMJITCompilationContext* con, int size, CVMBool isRef){ int spilloff, topoff; CVMBool isBusy; CVMJITSet* busySet = &con->RMcommonContext.spillBusySet; CVMUint8* refCount= con->RMcommonContext.spillBusyRefCount; CVMJITSet* refSet = &con->RMcommonContext.spillRefSet; CVMassert((size == 1) || (size == 2)); CVMassert((size == 1) || !isRef); for ( spilloff = con->maxPhiSize; ;spilloff += 1){ CVMJITsetContains(busySet, spilloff, isBusy); if (!isBusy){ /* this one is available. If double word, look for next, too. */ if (size > 1){ CVMJITsetContains(busySet, (spilloff+1), isBusy); if (!isBusy){ /* a pair of winners */ CVMJITsetAdd(con, busySet, spilloff); CVMJITsetAdd(con, busySet, spilloff+1); CVMJITsetRemove(con, refSet, spilloff); CVMJITsetRemove(con, refSet, spilloff+1); break; } /* else keep trying */ } else { /* a winner */ CVMJITsetAdd(con, busySet, spilloff); if (isRef){ CVMJITsetAdd(con, refSet, spilloff); } else { CVMJITsetRemove(con, refSet, spilloff); } break; } } } /* location spilloff is available. see if it is a new high water mark */ topoff = spilloff+size-1; if (topoff > con->RMcommonContext.maxSpillNumber){ con->RMcommonContext.maxSpillNumber = topoff; } if (topoff >= con->RMcommonContext.spillBusyRefSize){ resizeSpillRefCount(con, topoff+1); refCount= con->RMcommonContext.spillBusyRefCount; } refCount[spilloff] = 1; if (size > 1){ refCount[spilloff+1] = 1; } if (spilloff > CVMRM_MAX_SPILL_LOCATION) { CVMJITlimitExceeded(con, "exceeding max spill locations"); } return spilloff;}static voidrelinquishSpillLoc(CVMJITCompilationContext*con, int loc, int size){ CVMJITSet* busySet = &con->RMcommonContext.spillBusySet; CVMUint8* refCount= con->RMcommonContext.spillBusyRefCount; CVMassert(loc>=0); CVMassert((size == 1) || (size == 2));#ifdef CVM_DEBUG_ASSERTS { CVMBool isBusy; CVMJITsetContains(busySet, loc, isBusy); CVMassert(isBusy); CVMassert((loc+size) <= con->RMcommonContext.spillBusyRefSize); CVMassert(refCount[loc] > 0); if (size > 1){ CVMJITsetContains(busySet, (loc+1), isBusy); CVMassert(isBusy); CVMassert(refCount[loc+1] == refCount[loc]); } }#endif if (refCount[loc] == RM_STICKY_REF_COUNT) return; /* cannot deallocate */ if ((refCount[loc] -= 1) == 0){ CVMJITsetRemove(con, busySet, loc); if (size > 1){ CVMJITsetRemove(con, busySet, (loc+1)); } } if (size > 1){ refCount[loc+1] -= 1; }}static voidincrementSpillCount(CVMJITCompilationContext*con, int loc, int size){ CVMUint8* refCount= con->RMcommonContext.spillBusyRefCount; CVMassert((loc+size) <= con->RMcommonContext.spillBusyRefSize); if (refCount[loc] == RM_STICKY_REF_COUNT) return; /* maxed out */ refCount[loc] += 1; if (size > 1) refCount[loc+1] += 1;}static voidflushResource(CVMJITRMContext* con, CVMRMResource* rp){ CVMJITCompilationContext* cc = con->compilationContext; if (CVMRMisLocal(rp)) { CVMassert(rp->localNo != CVMRM_INVALID_LOCAL_NUMBER); /* spill directly to local */#if 0 /* Currently locals are write through, so there is no need to * spill them. However, because of the way the backend works * when we need to force evalauation node, it can lead to * a resource for a local being marked as dirty. We can * ignore these */ CVMCPUemitFrameReference(cc, RM_STORE_OPCODE(con,rp->size), rp->regno, CVMCPU_FRAME_LOCAL, rp->localNo);#endif#if 0 /* Sanity check to make sure the local is in sync. We'll load * the local into JFP since we know the local can't be there. * If it's 64bit, then we'll also use JSP. We also need to save * and restore these registers. */ if (rp->size == 2) { /* Save JSP and load 2nd word into it */ CVMCPUemitCCEEReferenceImmediate(cc, CVMCPU_STR32_OPCODE, CVMCPU_JSP_REG, offsetof(CVMCCExecEnv, ccmStorage) + sizeof(CVMUint32)); CVMCPUemitFrameReference(cc, CVMCPU_LDR32_OPCODE, CVMCPU_JSP_REG, CVMCPU_FRAME_LOCAL, rp->localNo+1); } /* Save JFP and load 1st word into it */ CVMCPUemitCCEEReferenceImmediate(cc, CVMCPU_STR32_OPCODE, CVMCPU_JFP_REG, offsetof(CVMCCExecEnv, ccmStorage)); /* this will trash JFP, so do it after the above frame ref */ CVMCPUemitFrameReference(cc, CVMCPU_LDR32_OPCODE, CVMCPU_JFP_REG, CVMCPU_FRAME_LOCAL, rp->localNo); /* this compare will ONLY work for integer registers!! */ CVMassert(con->key == RM_INT_KEY); CVMCPUemitCompareRegister(cc, CVMCPU_CMP_OPCODE, CVMCPU_COND_NE, CVMCPU_JFP_REG, rp->regno); if (rp->size == 2) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -