2008-06-30 15:33:41 -07:00
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */
2008-06-19 10:47:58 -07:00
/* ***** BEGIN LICENSE BLOCK *****
* Version : MPL 1.1 / GPL 2.0 / LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is [ Open Source Virtual Machine ] .
*
* The Initial Developer of the Original Code is
* Adobe System Incorporated .
* Portions created by the Initial Developer are Copyright ( C ) 2004 - 2007
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
* Adobe AS3 Team
*
* Alternatively , the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later ( the " GPL " ) , or
* the GNU Lesser General Public License Version 2.1 or later ( the " LGPL " ) ,
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above . If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL , and not to allow others to
* use your version of this file under the terms of the MPL , indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL . If you do not delete
* the provisions above , a recipient may use your version of this file under
* the terms of any one of the MPL , the GPL or the LGPL .
*
* * * * * * END LICENSE BLOCK * * * * * */
# include "nanojit.h"
namespace nanojit
{
# ifdef FEATURE_NANOJIT
using namespace avmplus ;
2008-07-15 13:06:05 -07:00
static uint32_t calcSaneCacheSize ( uint32_t in )
{
if ( in < uint32_t ( NJ_LOG2_PAGE_SIZE ) ) return NJ_LOG2_PAGE_SIZE ; // at least 1 page
if ( in > 30 ) return 30 ; // 1GB should be enough for anyone
return in ;
}
2008-06-19 10:47:58 -07:00
/**
* This is the main control center for creating and managing fragments .
*/
2008-07-15 13:06:05 -07:00
Fragmento : : Fragmento ( AvmCore * core , uint32_t cacheSizeLog2 )
: _allocList ( core - > GetGC ( ) ) ,
_max_pages ( 1 < < ( calcSaneCacheSize ( cacheSizeLog2 ) - NJ_LOG2_PAGE_SIZE ) )
2008-06-19 10:47:58 -07:00
{
2008-07-01 14:46:10 -07:00
# ifdef MEMORY_INFO
_allocList . set_meminfo_name ( " Fragmento._allocList " ) ;
# endif
2008-06-19 10:47:58 -07:00
_core = core ;
GC * gc = core - > GetGC ( ) ;
_frags = new ( gc ) FragmentMap ( gc , 128 ) ;
_assm = new ( gc ) nanojit : : Assembler ( this ) ;
2008-08-22 16:37:37 -07:00
_pageGrowth = 1 ;
2008-06-19 10:47:58 -07:00
verbose_only ( enterCounts = new ( gc ) BlockHist ( gc ) ; )
verbose_only ( mergeCounts = new ( gc ) BlockHist ( gc ) ; )
}
Fragmento : : ~ Fragmento ( )
{
2008-08-11 16:01:21 -07:00
clearFrags ( ) ;
2008-06-19 10:47:58 -07:00
_frags - > clear ( ) ;
while ( _allocList . size ( ) > 0 )
{
//fprintf(stderr,"dealloc %x\n", (intptr_t)_allocList.get(_allocList.size()-1));
2008-07-01 14:46:10 -07:00
# ifdef MEMORY_INFO
ChangeSizeExplicit ( " NanoJitMem " , - 1 , _gcHeap - > Size ( _allocList . last ( ) ) ) ;
# endif
2008-06-19 10:47:58 -07:00
_gcHeap - > Free ( _allocList . removeLast ( ) ) ;
}
2008-08-11 16:01:21 -07:00
delete _frags ;
delete _assm ;
# if defined(NJ_VERBOSE)
delete enterCounts ;
delete mergeCounts ;
# endif
2008-06-24 15:57:33 -07:00
NanoAssert ( _stats . freePages = = _stats . pages ) ;
2008-06-19 10:47:58 -07:00
}
2008-07-15 13:06:05 -07:00
void Fragmento : : trackFree ( int32_t delta )
{
_stats . freePages + = delta ;
const uint32_t pageUse = _stats . pages - _stats . freePages ;
if ( _stats . maxPageUse < pageUse )
_stats . maxPageUse = pageUse ;
}
2008-06-19 10:47:58 -07:00
Page * Fragmento : : pageAlloc ( )
{
NanoAssert ( sizeof ( Page ) = = NJ_PAGE_SIZE ) ;
2008-08-22 16:37:37 -07:00
if ( ! _pageList ) {
pagesGrow ( _pageGrowth ) ; // try to get more mem
if ( ( _pageGrowth < < 1 ) < _max_pages )
_pageGrowth < < = 1 ;
}
2008-06-19 10:47:58 -07:00
Page * page = _pageList ;
if ( page )
{
_pageList = page - > next ;
2008-07-15 13:06:05 -07:00
trackFree ( - 1 ) ;
2008-06-19 10:47:58 -07:00
}
//fprintf(stderr, "Fragmento::pageAlloc %X, %d free pages of %d\n", (int)page, _stats.freePages, _stats.pages);
2008-06-24 15:57:33 -07:00
NanoAssert ( pageCount ( ) = = _stats . freePages ) ;
2008-06-19 10:47:58 -07:00
return page ;
}
void Fragmento : : pageFree ( Page * page )
{
//fprintf(stderr, "Fragmento::pageFree %X, %d free pages of %d\n", (int)page, _stats.freePages+1, _stats.pages);
// link in the page
page - > next = _pageList ;
_pageList = page ;
2008-07-15 13:06:05 -07:00
trackFree ( + 1 ) ;
2008-06-24 15:57:33 -07:00
NanoAssert ( pageCount ( ) = = _stats . freePages ) ;
2008-06-19 10:47:58 -07:00
}
void Fragmento : : pagesGrow ( int32_t count )
{
NanoAssert ( ! _pageList ) ;
MMGC_MEM_TYPE ( " NanojitFragmentoMem " ) ;
Page * memory = 0 ;
2008-07-15 13:06:05 -07:00
if ( _stats . pages < _max_pages )
2008-06-19 10:47:58 -07:00
{
2008-08-22 16:37:37 -07:00
// make sure we don't grow beyond _max_pages
if ( _stats . pages + count > _max_pages )
count = _max_pages - _stats . pages ;
if ( count < 0 )
count = 0 ;
2008-06-19 10:47:58 -07:00
// @todo nastiness that needs a fix'n
_gcHeap = _core - > GetGC ( ) - > GetGCHeap ( ) ;
2008-07-15 13:06:05 -07:00
NanoAssert ( int32_t ( NJ_PAGE_SIZE ) < = _gcHeap - > kNativePageSize ) ;
2008-06-19 10:47:58 -07:00
2008-07-15 13:06:05 -07:00
// convert _max_pages to gc page count
2008-06-19 10:47:58 -07:00
int32_t gcpages = ( count * NJ_PAGE_SIZE ) / _gcHeap - > kNativePageSize ;
2008-07-15 13:06:05 -07:00
MMGC_MEM_TYPE ( " NanoJitMem " ) ;
2008-06-19 10:47:58 -07:00
memory = ( Page * ) _gcHeap - > Alloc ( gcpages ) ;
2008-07-01 14:46:10 -07:00
# ifdef MEMORY_INFO
ChangeSizeExplicit ( " NanoJitMem " , 1 , _gcHeap - > Size ( memory ) ) ;
# endif
2008-06-19 10:47:58 -07:00
NanoAssert ( ( int * ) memory = = pageTop ( memory ) ) ;
//fprintf(stderr,"head alloc of %d at %x of %d pages using nj page size of %d\n", gcpages, (intptr_t)memory, (intptr_t)_gcHeap->kNativePageSize, NJ_PAGE_SIZE);
2008-07-16 14:21:31 -07:00
_allocList . add ( memory ) ;
2008-06-19 10:47:58 -07:00
Page * page = memory ;
_pageList = page ;
_stats . pages + = count ;
2008-07-15 13:06:05 -07:00
_stats . freePages + = count ;
trackFree ( 0 ) ;
2008-06-19 10:47:58 -07:00
while ( - - count > 0 )
{
Page * next = page + 1 ;
//fprintf(stderr,"Fragmento::pageGrow adding page %x ; %d\n", (intptr_t)page, count);
page - > next = next ;
page = next ;
}
page - > next = 0 ;
2008-06-24 15:57:33 -07:00
NanoAssert ( pageCount ( ) = = _stats . freePages ) ;
2008-06-19 10:47:58 -07:00
//fprintf(stderr,"Fragmento::pageGrow adding page %x ; %d\n", (intptr_t)page, count);
}
}
void Fragmento : : clearFrags ( )
{
2008-06-24 15:57:33 -07:00
// reclaim any dangling native pages
_assm - > pageReset ( ) ;
2008-06-19 10:47:58 -07:00
while ( ! _frags - > isEmpty ( ) ) {
Fragment * f = _frags - > removeLast ( ) ;
2008-08-15 20:15:47 -07:00
Fragment * peer = f - > peer ;
while ( peer ) {
Fragment * next = peer - > peer ;
peer - > releaseTreeMem ( this ) ;
delete peer ;
peer = next ;
}
f - > releaseTreeMem ( this ) ;
2008-08-11 16:01:21 -07:00
delete f ;
2008-06-24 15:57:33 -07:00
}
2008-06-19 10:47:58 -07:00
verbose_only ( enterCounts - > clear ( ) ; )
verbose_only ( mergeCounts - > clear ( ) ; )
2008-06-24 15:57:33 -07:00
verbose_only ( _stats . flushes + + ) ;
verbose_only ( _stats . compiles = 0 ) ;
//fprintf(stderr, "Fragmento.clearFrags %d free pages of %d\n", _stats.freePages, _stats.pages);
2008-06-19 10:47:58 -07:00
}
Assembler * Fragmento : : assm ( )
{
return _assm ;
}
AvmCore * Fragmento : : core ( )
{
return _core ;
}
2008-08-15 20:15:47 -07:00
Fragment * Fragmento : : newLoop ( const void * ip )
{
Fragment * f = newFrag ( ip ) ;
2008-08-16 15:41:21 -07:00
Fragment * p = _frags - > get ( ip ) ;
2008-08-16 11:42:38 -07:00
if ( p ) {
2008-08-16 15:41:21 -07:00
f - > first = p ;
2008-08-16 11:42:38 -07:00
/* append at the end of the peer list */
Fragment * next ;
while ( ( next = p - > peer ) ! = NULL )
p = next ;
p - > peer = f ;
2008-08-16 15:41:21 -07:00
} else {
f - > first = f ;
2008-08-16 11:42:38 -07:00
_frags - > put ( ip , f ) ; /* this is the first fragment */
2008-08-16 15:41:21 -07:00
}
2008-08-15 20:15:47 -07:00
f - > anchor = f ;
f - > root = f ;
f - > kind = LoopTrace ;
f - > mergeCounts = new ( _core - > gc ) BlockHist ( _core - > gc ) ;
verbose_only ( addLabel ( f , " T " , _frags - > size ( ) ) ; )
return f ;
}
2008-07-07 02:47:40 -07:00
Fragment * Fragmento : : getLoop ( const void * ip )
2008-06-19 10:47:58 -07:00
{
2008-08-15 20:15:47 -07:00
return _frags - > get ( ip ) ;
2008-06-19 10:47:58 -07:00
}
# ifdef NJ_VERBOSE
void Fragmento : : addLabel ( Fragment * f , const char * prefix , int id )
{
char fragname [ 20 ] ;
sprintf ( fragname , " %s%d " , prefix , id ) ;
labels - > add ( f , sizeof ( Fragment ) , 0 , fragname ) ;
}
# endif
2008-07-07 02:47:40 -07:00
Fragment * Fragmento : : getMerge ( GuardRecord * lr , const void * ip )
2008-06-19 10:47:58 -07:00
{
Fragment * anchor = lr - > from - > anchor ;
for ( Fragment * f = anchor - > branches ; f ! = 0 ; f = f - > nextbranch ) {
2008-07-15 13:06:05 -07:00
if ( f - > kind = = MergeTrace & & f - > ip = = ip /*&& f->calldepth == lr->calldepth*/ ) {
2008-06-19 10:47:58 -07:00
// found existing shared branch on anchor
return f ;
}
}
2008-07-07 02:47:40 -07:00
Fragment * f = newBranch ( anchor , ip ) ;
2008-06-24 15:57:33 -07:00
f - > root = f ;
2008-06-19 10:47:58 -07:00
f - > kind = MergeTrace ;
f - > calldepth = lr - > calldepth ;
2008-07-15 13:06:05 -07:00
verbose_only (
int mergeid = 1 ;
for ( Fragment * g = anchor - > branches ; g ! = 0 ; g = g - > nextbranch )
if ( g - > kind = = MergeTrace )
mergeid + + ;
addLabel ( f , " M " , mergeid ) ;
)
2008-06-19 10:47:58 -07:00
return f ;
}
2008-07-07 02:47:40 -07:00
Fragment * Fragmento : : createBranch ( GuardRecord * lr , const void * ip )
2008-06-19 10:47:58 -07:00
{
Fragment * from = lr - > from ;
2008-07-07 02:47:40 -07:00
Fragment * f = newBranch ( from , ip ) ;
2008-06-19 10:47:58 -07:00
f - > kind = BranchTrace ;
f - > calldepth = lr - > calldepth ;
2008-06-24 15:57:33 -07:00
f - > treeBranches = f - > root - > treeBranches ;
f - > root - > treeBranches = f ;
2008-06-19 10:47:58 -07:00
return f ;
}
# ifdef NJ_VERBOSE
uint32_t Fragmento : : pageCount ( )
{
uint32_t n = 0 ;
for ( Page * page = _pageList ; page ; page = page - > next )
n + + ;
return n ;
}
2008-07-15 13:06:05 -07:00
struct fragstats {
int size ;
uint64_t traceDur ;
uint64_t interpDur ;
int lir , lirbytes ;
} ;
void Fragmento : : dumpFragStats ( Fragment * f , int level , fragstats & stat )
2008-06-19 10:47:58 -07:00
{
2008-07-08 17:09:53 -07:00
char buf [ 50 ] ;
sprintf ( buf , " %*c%s " , 1 + level , ' ' , labels - > format ( f ) ) ;
2008-06-19 10:47:58 -07:00
int called = f - > hits ( ) ;
if ( called > = 0 )
called + = f - > _called ;
else
called = - ( 1 < < f - > blacklistLevel ) - called - 1 ;
uint32_t main = f - > _native - f - > _exitNative ;
char cause [ 200 ] ;
if ( f - > _token & & strcmp ( f - > _token , " loop " ) = = 0 )
sprintf ( cause , " %s %d " , f - > _token , f - > xjumpCount ) ;
else if ( f - > _token ) {
if ( f - > eot_target ) {
sprintf ( cause , " %s %s " , f - > _token , labels - > format ( f - > eot_target ) ) ;
} else {
strcpy ( cause , f - > _token ) ;
}
}
else
cause [ 0 ] = 0 ;
2008-06-30 15:33:41 -07:00
2008-07-08 17:09:53 -07:00
_assm - > outputf ( " %-10s %7d %6d %6d %6d %4d %9llu %9llu %-12s %s " , buf ,
2008-06-19 10:47:58 -07:00
called , f - > guardCount , main , f - > _native , f - > compileNbr , f - > traceTicks / 1000 , f - > interpTicks / 1000 ,
2008-07-08 17:09:53 -07:00
cause , labels - > format ( f - > ip ) ) ;
2008-06-30 15:33:41 -07:00
2008-07-15 13:06:05 -07:00
stat . size + = main ;
stat . traceDur + = f - > traceTicks ;
stat . interpDur + = f - > interpTicks ;
stat . lir + = f - > _lir ;
stat . lirbytes + = f - > _lirbytes ;
2008-06-19 10:47:58 -07:00
for ( Fragment * x = f - > branches ; x ! = 0 ; x = x - > nextbranch )
if ( x - > kind ! = MergeTrace )
2008-07-15 13:06:05 -07:00
dumpFragStats ( x , level + 1 , stat ) ;
2008-06-19 10:47:58 -07:00
for ( Fragment * x = f - > branches ; x ! = 0 ; x = x - > nextbranch )
if ( x - > kind = = MergeTrace )
2008-07-15 13:06:05 -07:00
dumpFragStats ( x , level + 1 , stat ) ;
2008-06-19 10:47:58 -07:00
2008-06-24 15:57:33 -07:00
if ( f - > isAnchor ( ) & & f - > branches ! = 0 ) {
2008-06-19 10:47:58 -07:00
_assm - > output ( " " ) ;
}
}
class DurData { public :
DurData ( ) : frag ( 0 ) , traceDur ( 0 ) , interpDur ( 0 ) , size ( 0 ) { }
DurData ( int ) : frag ( 0 ) , traceDur ( 0 ) , interpDur ( 0 ) , size ( 0 ) { }
DurData ( Fragment * f , uint64_t td , uint64_t id , int32_t s )
: frag ( f ) , traceDur ( td ) , interpDur ( id ) , size ( s ) { }
Fragment * frag ;
uint64_t traceDur ;
uint64_t interpDur ;
int32_t size ;
} ;
void Fragmento : : dumpRatio ( const char * label , BlockHist * hist )
{
int total = 0 , unique = 0 ;
for ( int i = 0 , n = hist - > size ( ) ; i < n ; i + + ) {
const void * id = hist - > keyAt ( i ) ;
int c = hist - > get ( id ) ;
if ( c > 1 ) {
//_assm->outputf("%d %X", c, id);
unique + = 1 ;
}
else if ( c = = 1 ) {
unique + = 1 ;
}
total + = c ;
}
_assm - > outputf ( " %s total %d unique %d ratio %.1f% " , label , total , unique , double ( total ) / unique ) ;
}
void Fragmento : : dumpStats ( )
{
bool vsave = _assm - > _verbose ;
_assm - > _verbose = true ;
_assm - > output ( " " ) ;
dumpRatio ( " inline " , enterCounts ) ;
dumpRatio ( " merges " , mergeCounts ) ;
_assm - > outputf ( " abc %d il %d (%.1fx) abc+il %d (%.1fx) " ,
_stats . abcsize , _stats . ilsize , ( double ) _stats . ilsize / _stats . abcsize ,
_stats . abcsize + _stats . ilsize ,
double ( _stats . abcsize + _stats . ilsize ) / _stats . abcsize ) ;
int32_t count = _frags - > size ( ) ;
int32_t pages = _stats . pages ;
2008-07-15 13:06:05 -07:00
int32_t maxPageUse = _stats . maxPageUse ;
2008-06-19 10:47:58 -07:00
int32_t free = _stats . freePages ;
2008-06-24 15:57:33 -07:00
int32_t flushes = _stats . flushes ;
2008-06-19 10:47:58 -07:00
if ( ! count )
{
2008-06-24 15:57:33 -07:00
_assm - > outputf ( " No fragments in cache, %d flushes " , flushes ) ;
2008-06-19 10:47:58 -07:00
_assm - > _verbose = vsave ;
return ;
}
2008-06-24 15:57:33 -07:00
_assm - > outputf ( " \n Fragment statistics " ) ;
_assm - > outputf ( " loop trees: %d " , count ) ;
_assm - > outputf ( " flushes: %d " , flushes ) ;
_assm - > outputf ( " compiles: %d / %d " , _stats . compiles , _stats . totalCompiles ) ;
_assm - > outputf ( " used: %dk / %dk " , ( pages - free ) < < ( NJ_LOG2_PAGE_SIZE - 10 ) , pages < < ( NJ_LOG2_PAGE_SIZE - 10 ) ) ;
2008-07-15 13:06:05 -07:00
_assm - > outputf ( " maxPageUse: %dk " , ( maxPageUse ) < < ( NJ_LOG2_PAGE_SIZE - 10 ) ) ;
2008-07-08 17:09:53 -07:00
_assm - > output ( " \n trace calls guards main native gen T-trace T-interp " ) ;
2008-06-19 10:47:58 -07:00
avmplus : : SortedMap < uint64_t , DurData , avmplus : : LIST_NonGCObjects > durs ( _core - > gc ) ;
uint64_t totaldur = 0 ;
2008-07-15 13:06:05 -07:00
fragstats totalstat = { 0 , 0 , 0 , 0 , 0 } ;
2008-06-19 10:47:58 -07:00
for ( int32_t i = 0 ; i < count ; i + + )
{
Fragment * f = _frags - > at ( i ) ;
2008-08-15 20:15:47 -07:00
while ( true ) {
fragstats stat = { 0 , 0 , 0 , 0 , 0 } ;
dumpFragStats ( f , 0 , stat ) ;
if ( stat . lir ) {
totalstat . lir + = stat . lir ;
totalstat . lirbytes + = stat . lirbytes ;
}
uint64_t bothDur = stat . traceDur + stat . interpDur ;
if ( bothDur ) {
totalstat . interpDur + = stat . interpDur ;
totalstat . traceDur + = stat . traceDur ;
totalstat . size + = stat . size ;
totaldur + = bothDur ;
while ( durs . containsKey ( bothDur ) ) bothDur + + ;
DurData d ( f , stat . traceDur , stat . interpDur , stat . size ) ;
durs . put ( bothDur , d ) ;
}
if ( ! f - > peer )
break ;
f = f - > peer ;
2008-07-16 14:21:31 -07:00
}
2008-06-19 10:47:58 -07:00
}
2008-07-15 13:06:05 -07:00
uint64_t totaltrace = totalstat . traceDur ;
int totalsize = totalstat . size ;
2008-06-19 10:47:58 -07:00
_assm - > outputf ( " " ) ;
2008-07-16 14:21:31 -07:00
_assm - > outputf ( " lirbytes %d / lir %d = %.1f bytes/lir " , totalstat . lirbytes ,
totalstat . lir , double ( totalstat . lirbytes ) / totalstat . lir ) ;
2008-06-19 10:47:58 -07:00
_assm - > outputf ( " trace interp " ) ;
_assm - > outputf ( " %9lld (%2d%%) %9lld (%2d%%) " ,
totaltrace / 1000 , int ( 100.0 * totaltrace / totaldur ) ,
( totaldur - totaltrace ) / 1000 , int ( 100.0 * ( totaldur - totaltrace ) / totaldur ) ) ;
_assm - > outputf ( " " ) ;
_assm - > outputf ( " trace ticks trace interp size " ) ;
for ( int32_t i = durs . size ( ) - 1 ; i > = 0 ; i - - ) {
uint64_t bothDur = durs . keyAt ( i ) ;
DurData d = durs . get ( bothDur ) ;
int size = d . size ;
2008-07-08 17:09:53 -07:00
_assm - > outputf ( " %-4s %9lld (%2d%%) %9lld (%2d%%) %9lld (%2d%%) %6d (%2d%%) %s " ,
2008-06-19 10:47:58 -07:00
labels - > format ( d . frag ) ,
bothDur / 1000 , int ( 100.0 * bothDur / totaldur ) ,
d . traceDur / 1000 , int ( 100.0 * d . traceDur / totaldur ) ,
d . interpDur / 1000 , int ( 100.0 * d . interpDur / totaldur ) ,
2008-07-08 17:09:53 -07:00
size , int ( 100.0 * size / totalsize ) ,
labels - > format ( d . frag - > ip ) ) ;
2008-06-19 10:47:58 -07:00
}
_assm - > _verbose = vsave ;
}
2008-07-07 02:47:40 -07:00
void Fragmento : : countBlock ( BlockHist * hist , const void * ip )
2008-06-19 10:47:58 -07:00
{
int c = hist - > count ( ip ) ;
if ( _assm - > _verbose )
_assm - > outputf ( " ++ %s %d " , core ( ) - > interp . labels - > format ( ip ) , c ) ;
}
void Fragmento : : countIL ( uint32_t il , uint32_t abc )
{
_stats . ilsize + = il ;
_stats . abcsize + = abc ;
}
2008-06-30 15:33:41 -07:00
# ifdef AVMPLUS_VERBOSE
2008-07-31 13:28:12 -07:00
void Fragmento : : drawTrees ( char * fileName ) {
2008-06-30 15:33:41 -07:00
drawTraceTrees ( this , this - > _frags , this - > _core , fileName ) ;
}
# endif
2008-06-19 10:47:58 -07:00
# endif // NJ_VERBOSE
//
// Fragment
//
2008-07-07 02:47:40 -07:00
Fragment : : Fragment ( const void * _ip ) : ip ( _ip )
2008-06-19 10:47:58 -07:00
{
// Fragment is a gc object which is zero'd by the GC, no need to clear fields
}
2008-06-24 15:57:33 -07:00
Fragment : : ~ Fragment ( )
{
2008-08-11 16:01:21 -07:00
onDestroy ( ) ;
2008-06-24 15:57:33 -07:00
NanoAssert ( _pages = = 0 ) ;
}
2008-06-19 10:47:58 -07:00
void Fragment : : addLink ( GuardRecord * lnk )
{
//fprintf(stderr,"addLink %x from %X target %X\n",(int)lnk,(int)lnk->from,(int)lnk->target);
lnk - > next = _links ;
_links = lnk ;
}
void Fragment : : removeLink ( GuardRecord * lnk )
{
GuardRecord * lr = _links ;
GuardRecord * * lrp = & _links ;
while ( lr )
{
if ( lr = = lnk )
{
* lrp = lr - > next ;
lnk - > next = 0 ;
break ;
}
lrp = & ( lr - > next ) ;
lr = lr - > next ;
}
}
void Fragment : : link ( Assembler * assm )
{
// patch all jumps into this fragment
GuardRecord * lr = _links ;
while ( lr )
{
GuardRecord * next = lr - > next ;
Fragment * from = lr - > target ;
if ( from & & from - > fragEntry ) assm - > patch ( lr ) ;
lr = next ;
}
// and then patch all jumps leading out
lr = outbound ;
while ( lr )
{
GuardRecord * next = lr - > outgoing ;
Fragment * targ = lr - > target ;
if ( targ & & targ - > fragEntry ) assm - > patch ( lr ) ;
lr = next ;
}
}
void Fragment : : unlink ( Assembler * assm )
{
// remove our guards from others' in-bound list, so they don't patch to us
GuardRecord * lr = outbound ;
while ( lr )
{
GuardRecord * next = lr - > outgoing ;
Fragment * targ = lr - > target ;
if ( targ ) targ - > removeLink ( lr ) ;
lr = next ;
}
// then unpatch all jumps into this fragment
lr = _links ;
while ( lr )
{
GuardRecord * next = lr - > next ;
Fragment * from = lr - > target ;
if ( from & & from - > fragEntry ) assm - > unpatch ( lr ) ;
lr = next ;
}
}
2008-06-24 15:57:33 -07:00
# ifdef _DEBUG
2008-06-19 10:47:58 -07:00
bool Fragment : : hasOnlyTreeLinks ( )
{
// check that all incoming links are on the same tree
bool isIt = true ;
GuardRecord * lr = _links ;
while ( lr )
{
GuardRecord * next = lr - > next ;
NanoAssert ( lr - > target = = this ) ; // def'n of GuardRecord
2008-06-24 15:57:33 -07:00
if ( lr - > from - > root ! = root )
2008-06-19 10:47:58 -07:00
{
isIt = false ;
break ;
}
lr = next ;
}
return isIt ;
}
2008-06-24 15:57:33 -07:00
# endif
2008-06-19 10:47:58 -07:00
void Fragment : : removeIntraLinks ( )
{
// should only be called on root of tree
2008-06-24 15:57:33 -07:00
NanoAssert ( isRoot ( ) ) ;
2008-06-19 10:47:58 -07:00
GuardRecord * lr = _links ;
while ( lr )
{
GuardRecord * next = lr - > next ;
NanoAssert ( lr - > target = = this ) ; // def'n of GuardRecord
2008-06-24 15:57:33 -07:00
if ( lr - > from - > root = = root )
2008-06-19 10:47:58 -07:00
removeLink ( lr ) ;
lr = next ;
}
}
void Fragment : : unlinkBranches ( Assembler * /*assm*/ )
{
// should only be called on root of tree
2008-06-24 15:57:33 -07:00
NanoAssert ( isRoot ( ) ) ;
2008-06-19 10:47:58 -07:00
Fragment * frag = treeBranches ;
while ( frag )
{
NanoAssert ( frag - > kind = = BranchTrace & & frag - > hasOnlyTreeLinks ( ) ) ;
frag - > _links = 0 ;
frag - > fragEntry = 0 ;
frag = frag - > treeBranches ;
}
}
void Fragment : : linkBranches ( Assembler * assm )
{
// should only be called on root of tree
2008-06-24 15:57:33 -07:00
NanoAssert ( isRoot ( ) ) ;
2008-06-19 10:47:58 -07:00
Fragment * frag = treeBranches ;
while ( frag )
{
if ( frag - > fragEntry ) frag - > link ( assm ) ;
frag = frag - > treeBranches ;
}
}
void Fragment : : blacklist ( )
{
blacklistLevel + + ;
_hits = - ( 1 < < blacklistLevel ) ;
}
2008-07-07 02:47:40 -07:00
Fragment * Fragmento : : newFrag ( const void * ip )
2008-06-19 10:47:58 -07:00
{
GC * gc = _core - > gc ;
2008-07-07 02:47:40 -07:00
Fragment * f = new ( gc ) Fragment ( ip ) ;
2008-06-19 10:47:58 -07:00
f - > blacklistLevel = 5 ;
return f ;
}
2008-07-07 02:47:40 -07:00
Fragment * Fragmento : : newBranch ( Fragment * from , const void * ip )
2008-06-19 10:47:58 -07:00
{
2008-07-07 02:47:40 -07:00
Fragment * f = newFrag ( ip ) ;
2008-06-19 10:47:58 -07:00
f - > anchor = from - > anchor ;
2008-06-24 15:57:33 -07:00
f - > root = from - > root ;
2008-06-19 10:47:58 -07:00
f - > mergeCounts = from - > anchor - > mergeCounts ;
f - > xjumpCount = from - > xjumpCount ;
/*// prepend
f - > nextbranch = from - > branches ;
from - > branches = f ; */
// append
if ( ! from - > branches ) {
from - > branches = f ;
} else {
Fragment * p = from - > branches ;
while ( p - > nextbranch ! = 0 )
p = p - > nextbranch ;
p - > nextbranch = f ;
}
return f ;
}
2008-06-24 15:57:33 -07:00
void Fragment : : releaseLirBuffer ( )
{
lastIns = 0 ;
}
2008-06-19 10:47:58 -07:00
2008-06-24 15:57:33 -07:00
void Fragment : : releaseCode ( Fragmento * frago )
{
_code = 0 ;
while ( _pages )
{
Page * next = _pages - > next ;
frago - > pageFree ( _pages ) ;
_pages = next ;
}
}
void Fragment : : releaseTreeMem ( Fragmento * frago )
{
releaseLirBuffer ( ) ;
releaseCode ( frago ) ;
2008-08-18 12:32:14 -07:00
2008-06-24 15:57:33 -07:00
// now do it for all branches
Fragment * branch = branches ;
while ( branch )
{
Fragment * next = branch - > nextbranch ;
branch - > releaseTreeMem ( frago ) ; // @todo safer here to recurse in case we support nested trees
2008-08-11 16:01:21 -07:00
delete branch ;
2008-06-24 15:57:33 -07:00
branch = next ;
}
}
2008-06-19 10:47:58 -07:00
# endif /* FEATURE_NANOJIT */
}
2008-06-30 15:33:41 -07:00