/[jscoverage]/trunk/js/jsgc.cpp
ViewVC logotype

Diff of /trunk/js/jsgc.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 506 by siliconforks, Sat Sep 26 23:15:22 2009 UTC revision 507 by siliconforks, Sun Jan 10 07:23:34 2010 UTC
# Line 1  Line 1 
1  /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-  /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2   * vim: set ts=8 sw=4 et tw=78:   * vim: set ts=8 sw=4 et tw=78:
3   *   *
4   * ***** BEGIN LICENSE BLOCK *****   * ***** BEGIN LICENSE BLOCK *****
# Line 48  Line 48 
48   *   *
49   * XXX swizzle page to freelist for better locality of reference   * XXX swizzle page to freelist for better locality of reference
50   */   */
 #include "jsstddef.h"  
51  #include <stdlib.h>     /* for free */  #include <stdlib.h>     /* for free */
52  #include <math.h>  #include <math.h>
53  #include <string.h>     /* for memset used when DEBUG */  #include <string.h>     /* for memset used when DEBUG */
54  #include "jstypes.h"  #include "jstypes.h"
55    #include "jsstdint.h"
56  #include "jsutil.h" /* Added by JSIFY */  #include "jsutil.h" /* Added by JSIFY */
57  #include "jshash.h" /* Added by JSIFY */  #include "jshash.h" /* Added by JSIFY */
58  #include "jsbit.h"  #include "jsbit.h"
# Line 76  Line 76 
76  #include "jsscript.h"  #include "jsscript.h"
77  #include "jsstaticcheck.h"  #include "jsstaticcheck.h"
78  #include "jsstr.h"  #include "jsstr.h"
79    #include "jstask.h"
80  #include "jstracer.h"  #include "jstracer.h"
81    
82  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
83  #include "jsxml.h"  #include "jsxml.h"
84  #endif  #endif
85    
86    #ifdef INCLUDE_MOZILLA_DTRACE
87    #include "jsdtracef.h"
88    #endif
89    
90  /*  /*
91   * Check if posix_memalign is available.   * Check if posix_memalign is available.
92   */   */
# Line 110  Line 115 
115  #   define JS_GC_USE_MMAP 1  #   define JS_GC_USE_MMAP 1
116  #  endif  #  endif
117  #  include <windows.h>  #  include <windows.h>
118    # elif defined(__SYMBIAN32__)
119    // Symbian's OpenC has mmap (and #defines _POSIX_MAPPED_FILES), but
120    // doesn't implement MAP_ANON.  If we have MOZ_MEMORY, then we can use
121    // posix_memalign; we've defined HAS_POSIX_MEMALIGN above.  Otherwise,
122    // we overallocate.
123  # else  # else
124  #  if defined(XP_UNIX) || defined(XP_BEOS)  #  if defined(XP_UNIX) || defined(XP_BEOS)
125  #   include <unistd.h>  #   include <unistd.h>
# Line 143  Line 153 
153  JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(jsval));  JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(jsval));
154  JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(void *));  JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(void *));
155    
   
156  /*  /*
157   * Check that JSTRACE_XML follows JSTRACE_OBJECT, JSTRACE_DOUBLE and   * Check that JSTRACE_XML follows JSTRACE_OBJECT, JSTRACE_DOUBLE and
158   * JSTRACE_STRING.   * JSTRACE_STRING.
# Line 432  Line 441 
441      ((GC_ARENA_SIZE - (uint32) sizeof(JSGCArenaInfo)) / ((thingSize) + 1U))      ((GC_ARENA_SIZE - (uint32) sizeof(JSGCArenaInfo)) / ((thingSize) + 1U))
442    
443  #define THING_TO_ARENA(thing)                                                 \  #define THING_TO_ARENA(thing)                                                 \
444      ((JSGCArenaInfo *)(((jsuword) (thing) | GC_ARENA_MASK) +                  \      (JS_ASSERT(!JSString::isStatic(thing)),                                   \
445                         1 - sizeof(JSGCArenaInfo)))       (JSGCArenaInfo *)(((jsuword) (thing) | GC_ARENA_MASK)                    \
446                           + 1 - sizeof(JSGCArenaInfo)))
447    
448  #define THING_TO_INDEX(thing, thingSize)                                      \  #define THING_TO_INDEX(thing, thingSize)                                      \
449      ((uint32) ((jsuword) (thing) & GC_ARENA_MASK) / (uint32) (thingSize))      ((uint32) ((jsuword) (thing) & GC_ARENA_MASK) / (uint32) (thingSize))
# Line 642  Line 652 
652   * The maximum number of things to put on the local free list by taking   * The maximum number of things to put on the local free list by taking
653   * several things from the global free list or from the tail of the last   * several things from the global free list or from the tail of the last
654   * allocated arena to amortize the cost of rt->gcLock.   * allocated arena to amortize the cost of rt->gcLock.
  *  
  * We use number 8 based on benchmarks from bug 312238.  
655   */   */
656  #define MAX_THREAD_LOCAL_THINGS 8  #define MAX_THREAD_LOCAL_THINGS 64
657    
658  #endif  #endif
659    
# Line 715  Line 723 
723  {  {
724      if (table->array) {      if (table->array) {
725          JS_ASSERT(table->count > 0);          JS_ASSERT(table->count > 0);
726          free(table->array);          js_free(table->array);
727          table->array = NULL;          table->array = NULL;
728          table->count = 0;          table->count = 0;
729      }      }
# Line 749  Line 757 
757              if (capacity > (size_t)-1 / sizeof table->array[0])              if (capacity > (size_t)-1 / sizeof table->array[0])
758                  goto bad;                  goto bad;
759          }          }
760          array = (void **) realloc(table->array,          array = (void **) js_realloc(table->array,
761                                    capacity * sizeof table->array[0]);                                       capacity * sizeof table->array[0]);
762          if (!array)          if (!array)
763              goto bad;              goto bad;
764  #ifdef DEBUG  #ifdef DEBUG
# Line 789  Line 797 
797          array = table->array;          array = table->array;
798          JS_ASSERT(array);          JS_ASSERT(array);
799          if (capacity == 0) {          if (capacity == 0) {
800              free(array);              js_free(array);
801              table->array = NULL;              table->array = NULL;
802              return;              return;
803          }          }
804          array = (void **) realloc(array, capacity * sizeof array[0]);          array = (void **) js_realloc(array, capacity * sizeof array[0]);
805          if (array)          if (array)
806              table->array = array;              table->array = array;
807      }      }
# Line 874  Line 882 
882       *       *
883       * bytes to ensure that we always have room to store the gap.       * bytes to ensure that we always have room to store the gap.
884       */       */
885      p = malloc((js_gcArenasPerChunk + 1) << GC_ARENA_SHIFT);      p = js_malloc((js_gcArenasPerChunk + 1) << GC_ARENA_SHIFT);
886      if (!p)      if (!p)
887          return 0;          return 0;
888    
# Line 906  Line 914 
914  #endif  #endif
915    
916  #if HAS_POSIX_MEMALIGN  #if HAS_POSIX_MEMALIGN
917      free((void *) chunk);      js_free((void *) chunk);
918  #else  #else
919      /* See comments in NewGCChunk. */      /* See comments in NewGCChunk. */
920      JS_ASSERT(*GetMallocedChunkGapPtr(chunk) < GC_ARENA_SIZE);      JS_ASSERT(*GetMallocedChunkGapPtr(chunk) < GC_ARENA_SIZE);
921      free((void *) (chunk - *GetMallocedChunkGapPtr(chunk)));      js_free((void *) (chunk - *GetMallocedChunkGapPtr(chunk)));
922  #endif  #endif
923  }  }
924    
# Line 1085  Line 1093 
1093      for (i = 0; i < GC_NUM_FREELISTS; i++) {      for (i = 0; i < GC_NUM_FREELISTS; i++) {
1094          arenaList = &rt->gcArenaList[i];          arenaList = &rt->gcArenaList[i];
1095          thingSize = GC_FREELIST_NBYTES(i);          thingSize = GC_FREELIST_NBYTES(i);
         JS_ASSERT((size_t)(uint16)thingSize == thingSize);  
1096          arenaList->last = NULL;          arenaList->last = NULL;
1097          arenaList->lastCount = (uint16) THINGS_PER_ARENA(thingSize);          arenaList->lastCount = THINGS_PER_ARENA(thingSize);
1098          arenaList->thingSize = (uint16) thingSize;          arenaList->thingSize = thingSize;
1099          arenaList->freeList = NULL;          arenaList->freeList = NULL;
1100      }      }
1101      rt->gcDoubleArenaList.first = NULL;      rt->gcDoubleArenaList.first = NULL;
# Line 1139  Line 1146 
1146      JSGCArenaInfo *a;      JSGCArenaInfo *a;
1147      uint32 index;      uint32 index;
1148    
1149        if (JSString::isStatic(thing))
1150            return NULL;
1151      a = THING_TO_ARENA(thing);      a = THING_TO_ARENA(thing);
1152      if (!a->list)      if (!a->list)
1153          return NULL;          return NULL;
# Line 1149  Line 1158 
1158  intN  intN
1159  js_GetExternalStringGCType(JSString *str)  js_GetExternalStringGCType(JSString *str)
1160  {  {
1161      uintN type;      JS_ASSERT(!JSString::isStatic(str));
1162    
1163      type = (uintN) *GetGCThingFlags(str) & GCF_TYPEMASK;      uintN type = (uintN) *GetGCThingFlags(str) & GCF_TYPEMASK;
1164      JS_ASSERT(type == GCX_STRING || type >= GCX_EXTERNAL_STRING);      JS_ASSERT(type == GCX_STRING || type >= GCX_EXTERNAL_STRING);
1165      return (type == GCX_STRING) ? -1 : (intN) (type - GCX_EXTERNAL_STRING);      return (type == GCX_STRING) ? -1 : (intN) (type - GCX_EXTERNAL_STRING);
1166  }  }
# Line 1173  Line 1182 
1182      JSGCArenaInfo *a;      JSGCArenaInfo *a;
1183      uint32 index;      uint32 index;
1184    
1185        if (JSString::isStatic(thing))
1186            return JSTRACE_STRING;
1187    
1188      a = THING_TO_ARENA(thing);      a = THING_TO_ARENA(thing);
1189      if (!a->list)      if (!a->list)
1190          return JSTRACE_DOUBLE;          return JSTRACE_DOUBLE;
# Line 1200  Line 1212 
1212      JSGCArenaInfo *a;      JSGCArenaInfo *a;
1213      uint32 index, flags;      uint32 index, flags;
1214    
1215        if (JSString::isStatic(thing))
1216            return false;
1217    
1218      a = THING_TO_ARENA(thing);      a = THING_TO_ARENA(thing);
1219      if (!a->list) {      if (!a->list) {
1220          /*          /*
# Line 1302  Line 1317 
1317       * By default the trigger factor gets maximum possible value. This       * By default the trigger factor gets maximum possible value. This
1318       * means that GC will not be triggered by growth of GC memory (gcBytes).       * means that GC will not be triggered by growth of GC memory (gcBytes).
1319       */       */
1320      rt->gcTriggerFactor = (uint32) -1;      rt->setGCTriggerFactor((uint32) -1);
1321    
1322      /*      /*
1323       * The assigned value prevents GC from running when GC memory is too low       * The assigned value prevents GC from running when GC memory is too low
1324       * (during JS engine start).       * (during JS engine start).
1325       */       */
1326      rt->gcLastBytes = 8192;      rt->setGCLastBytes(8192);
1327    
1328      METER(memset(&rt->gcStats, 0, sizeof rt->gcStats));      METER(memset(&rt->gcStats, 0, sizeof rt->gcStats));
1329      return JS_TRUE;      return JS_TRUE;
# Line 1467  Line 1482 
1482  CheckLeakedRoots(JSRuntime *rt);  CheckLeakedRoots(JSRuntime *rt);
1483  #endif  #endif
1484    
 #ifdef JS_THREADSAFE  
 static void  
 TrimGCFreeListsPool(JSRuntime *rt, uintN keepCount);  
 #endif  
   
1485  void  void
1486  js_FinishGC(JSRuntime *rt)  js_FinishGC(JSRuntime *rt)
1487  {  {
# Line 1483  Line 1493 
1493  #endif  #endif
1494    
1495      FreePtrTable(&rt->gcIteratorTable, &iteratorTableInfo);      FreePtrTable(&rt->gcIteratorTable, &iteratorTableInfo);
 #ifdef JS_THREADSAFE  
     TrimGCFreeListsPool(rt, 0);  
     JS_ASSERT(!rt->gcFreeListsPool);  
 #endif  
1496      FinishGCArenaLists(rt);      FinishGCArenaLists(rt);
1497    
1498      if (rt->gcRootsHash.ops) {      if (rt->gcRootsHash.ops) {
# Line 1726  Line 1732 
1732  unsigned gchpos = 0;  unsigned gchpos = 0;
1733  #endif  #endif
1734    
1735  #ifdef JS_THREADSAFE  void
1736    JSRuntime::setGCTriggerFactor(uint32 factor)
 const JSGCFreeListSet js_GCEmptyFreeListSet = {  
     { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, NULL  
 };  
   
 static void  
 TrimGCFreeListsPool(JSRuntime *rt, uintN keepCount)  
1737  {  {
1738      JSGCFreeListSet **cursor, *freeLists, *link;      JS_ASSERT(factor >= 100);
1739    
1740      cursor = &rt->gcFreeListsPool;      gcTriggerFactor = factor;
1741      while (keepCount != 0) {      setGCLastBytes(gcLastBytes);
         --keepCount;  
         freeLists = *cursor;  
         if (!freeLists)  
             return;  
         memset(freeLists->array, 0, sizeof freeLists->array);  
         cursor = &freeLists->link;  
     }  
     freeLists = *cursor;  
     if (freeLists) {  
         *cursor = NULL;  
         do {  
             link = freeLists->link;  
             free(freeLists);  
         } while ((freeLists = link) != NULL);  
     }  
1742  }  }
1743    
1744  void  void
1745  js_RevokeGCLocalFreeLists(JSContext *cx)  JSRuntime::setGCLastBytes(size_t lastBytes)
 {  
     JS_ASSERT(!cx->gcLocalFreeLists->link);  
     if (cx->gcLocalFreeLists != &js_GCEmptyFreeListSet) {  
         cx->gcLocalFreeLists->link = cx->runtime->gcFreeListsPool;  
         cx->runtime->gcFreeListsPool = cx->gcLocalFreeLists;  
         cx->gcLocalFreeLists = (JSGCFreeListSet *) &js_GCEmptyFreeListSet;  
     }  
 }  
   
 static JSGCFreeListSet *  
 EnsureLocalFreeList(JSContext *cx)  
1746  {  {
1747      JSGCFreeListSet *freeLists;      gcLastBytes = lastBytes;
1748        uint64 triggerBytes = uint64(lastBytes) * uint64(gcTriggerFactor / 100);
1749      freeLists = cx->gcLocalFreeLists;      if (triggerBytes != size_t(triggerBytes))
1750      if (freeLists != &js_GCEmptyFreeListSet) {          triggerBytes = size_t(-1);
1751          JS_ASSERT(freeLists);      gcTriggerBytes = size_t(triggerBytes);
         return freeLists;  
     }  
   
     freeLists = cx->runtime->gcFreeListsPool;  
     if (freeLists) {  
         cx->runtime->gcFreeListsPool = freeLists->link;  
         freeLists->link = NULL;  
     } else {  
         /* JS_malloc is not used as the caller reports out-of-memory itself. */  
         freeLists = (JSGCFreeListSet *) calloc(1, sizeof *freeLists);  
         if (!freeLists)  
             return NULL;  
     }  
     cx->gcLocalFreeLists = freeLists;  
     return freeLists;  
1752  }  }
1753    
 #endif  
   
1754  static JS_INLINE bool  static JS_INLINE bool
1755  IsGCThresholdReached(JSRuntime *rt)  IsGCThresholdReached(JSRuntime *rt)
1756  {  {
# Line 1808  Line 1765 
1765       * the gcBytes value is close to zero at the JS engine start.       * the gcBytes value is close to zero at the JS engine start.
1766       */       */
1767      return rt->gcMallocBytes >= rt->gcMaxMallocBytes ||      return rt->gcMallocBytes >= rt->gcMaxMallocBytes ||
1768             rt->gcBytes / rt->gcTriggerFactor >= rt->gcLastBytes / 100;             rt->gcBytes >= rt->gcTriggerBytes;
1769  }  }
1770    
1771  void *  template <class T> static JS_INLINE T*
1772  js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)  NewGCThing(JSContext *cx, uintN flags)
1773  {  {
1774      JSRuntime *rt;      JSRuntime *rt;
     uintN flindex;  
1775      bool doGC;      bool doGC;
1776      JSGCThing *thing;      JSGCThing *thing;
1777      uint8 *flagp;      uint8 *flagp;
# Line 1829  Line 1785 
1785  #ifdef JS_THREADSAFE  #ifdef JS_THREADSAFE
1786      JSBool gcLocked;      JSBool gcLocked;
1787      uintN localMallocBytes;      uintN localMallocBytes;
     JSGCFreeListSet *freeLists;  
1788      JSGCThing **lastptr;      JSGCThing **lastptr;
1789      JSGCThing *tmpthing;      JSGCThing *tmpthing;
1790      uint8 *tmpflagp;      uint8 *tmpflagp;
# Line 1838  Line 1793 
1793    
1794      JS_ASSERT((flags & GCF_TYPEMASK) != GCX_DOUBLE);      JS_ASSERT((flags & GCF_TYPEMASK) != GCX_DOUBLE);
1795      rt = cx->runtime;      rt = cx->runtime;
1796      nbytes = JS_ROUNDUP(nbytes, sizeof(JSGCThing));      size_t nbytes = sizeof(T);
1797      flindex = GC_FREELIST_INDEX(nbytes);      JS_ASSERT(JS_ROUNDUP(nbytes, sizeof(JSGCThing)) == nbytes);
1798        uintN flindex = GC_FREELIST_INDEX(nbytes);
1799    
1800      /* Updates of metering counters here may not be thread-safe. */      /* Updates of metering counters here may not be thread-safe. */
1801      METER(astats = &cx->runtime->gcStats.arenaStats[flindex]);      METER(astats = &cx->runtime->gcStats.arenaStats[flindex]);
# Line 1848  Line 1804 
1804  #ifdef JS_THREADSAFE  #ifdef JS_THREADSAFE
1805      gcLocked = JS_FALSE;      gcLocked = JS_FALSE;
1806      JS_ASSERT(cx->thread);      JS_ASSERT(cx->thread);
1807      freeLists = cx->gcLocalFreeLists;  
1808      thing = freeLists->array[flindex];      JSGCThing *&freeList = cx->thread->gcFreeLists[flindex];
1809      localMallocBytes = cx->thread->gcMallocBytes;      thing = freeList;
1810        localMallocBytes = JS_THREAD_DATA(cx)->gcMallocBytes;
1811      if (thing && rt->gcMaxMallocBytes - rt->gcMallocBytes > localMallocBytes) {      if (thing && rt->gcMaxMallocBytes - rt->gcMallocBytes > localMallocBytes) {
1812          flagp = thing->flagp;          flagp = thing->flagp;
1813          freeLists->array[flindex] = thing->next;          freeList = thing->next;
1814          METER(astats->localalloc++);          METER(astats->localalloc++);
1815          goto success;          goto success;
1816      }      }
# Line 1863  Line 1820 
1820    
1821      /* Transfer thread-local counter to global one. */      /* Transfer thread-local counter to global one. */
1822      if (localMallocBytes != 0) {      if (localMallocBytes != 0) {
1823          cx->thread->gcMallocBytes = 0;          JS_THREAD_DATA(cx)->gcMallocBytes = 0;
1824          if (rt->gcMaxMallocBytes - rt->gcMallocBytes < localMallocBytes)          if (rt->gcMaxMallocBytes - rt->gcMallocBytes < localMallocBytes)
1825              rt->gcMallocBytes = rt->gcMaxMallocBytes;              rt->gcMallocBytes = rt->gcMaxMallocBytes;
1826          else          else
# Line 1912  Line 1869 
1869  #ifdef JS_THREADSAFE  #ifdef JS_THREADSAFE
1870              /*              /*
1871               * Refill the local free list by taking several things from the               * Refill the local free list by taking several things from the
1872               * global free list unless we are still at rt->gcMaxMallocBytes               * global free list unless the free list is already populated or
1873               * barrier or the free list is already populated. The former               * we are still at rt->gcMaxMallocBytes barrier. The former is
1874               * happens when GC is canceled due to gcCallback(cx, JSGC_BEGIN)               * caused via allocating new things in gcCallback(cx, JSGC_END).
1875               * returning false. The latter is caused via allocating new               * The latter happens when GC is canceled due to
1876               * things in gcCallback(cx, JSGC_END).               * gcCallback(cx, JSGC_BEGIN) returning false.
1877               */               */
1878              if (rt->gcMallocBytes >= rt->gcMaxMallocBytes)              if (freeList || rt->gcMallocBytes >= rt->gcMaxMallocBytes)
                 break;  
   
             freeLists = EnsureLocalFreeList(cx);  
             if (!freeLists)  
                 goto fail;  
             if (freeLists->array[flindex])  
1879                  break;                  break;
1880    
1881              tmpthing = arenaList->freeList;              tmpthing = arenaList->freeList;
# Line 1936  Line 1887 
1887                      tmpthing = tmpthing->next;                      tmpthing = tmpthing->next;
1888                  } while (--maxFreeThings != 0);                  } while (--maxFreeThings != 0);
1889    
1890                  freeLists->array[flindex] = arenaList->freeList;                  freeList = arenaList->freeList;
1891                  arenaList->freeList = tmpthing->next;                  arenaList->freeList = tmpthing->next;
1892                  tmpthing->next = NULL;                  tmpthing->next = NULL;
1893              }              }
# Line 1994  Line 1945 
1945           * arena. Prefer to order free things by ascending address in the           * arena. Prefer to order free things by ascending address in the
1946           * (unscientific) hope of better cache locality.           * (unscientific) hope of better cache locality.
1947           */           */
1948          if (rt->gcMallocBytes >= rt->gcMaxMallocBytes)          if (freeList || rt->gcMallocBytes >= rt->gcMaxMallocBytes)
1949              break;              break;
1950            lastptr = &freeList;
         freeLists = EnsureLocalFreeList(cx);  
         if (!freeLists)  
             goto fail;  
         if (freeLists->array[flindex])  
             break;  
         lastptr = &freeLists->array[flindex];  
1951          maxFreeThings = thingsLimit - arenaList->lastCount;          maxFreeThings = thingsLimit - arenaList->lastCount;
1952          if (maxFreeThings > MAX_THREAD_LOCAL_THINGS)          if (maxFreeThings > MAX_THREAD_LOCAL_THINGS)
1953              maxFreeThings = MAX_THREAD_LOCAL_THINGS;              maxFreeThings = MAX_THREAD_LOCAL_THINGS;
1954            uint32 lastCount = arenaList->lastCount;
1955          while (maxFreeThings != 0) {          while (maxFreeThings != 0) {
1956              --maxFreeThings;              --maxFreeThings;
1957    
1958              tmpflagp = THING_FLAGP(a, arenaList->lastCount);              tmpflagp = THING_FLAGP(a, lastCount);
1959              tmpthing = FLAGP_TO_THING(tmpflagp, nbytes);              tmpthing = FLAGP_TO_THING(tmpflagp, nbytes);
1960              arenaList->lastCount++;              lastCount++;
1961              tmpthing->flagp = tmpflagp;              tmpthing->flagp = tmpflagp;
1962              *tmpflagp = GCF_FINAL;    /* signifying that thing is free */              *tmpflagp = GCF_FINAL;    /* signifying that thing is free */
1963    
# Line 2019  Line 1965 
1965              lastptr = &tmpthing->next;              lastptr = &tmpthing->next;
1966          }          }
1967          *lastptr = NULL;          *lastptr = NULL;
1968            arenaList->lastCount = lastCount;
1969  #endif  #endif
1970          break;          break;
1971      }      }
# Line 2071  Line 2018 
2018      if (gcLocked)      if (gcLocked)
2019          JS_UNLOCK_GC(rt);          JS_UNLOCK_GC(rt);
2020  #endif  #endif
2021      return thing;      return (T*)thing;
2022    
2023  fail:  fail:
2024  #ifdef JS_THREADSAFE  #ifdef JS_THREADSAFE
# Line 2083  Line 2030 
2030      return NULL;      return NULL;
2031  }  }
2032    
2033    extern JSObject* js_NewGCObject(JSContext *cx, uintN flags)
2034    {
2035        return NewGCThing<JSObject>(cx, flags);
2036    }
2037    
2038    extern JSString* js_NewGCString(JSContext *cx, uintN flags)
2039    {
2040        return NewGCThing<JSString>(cx, flags);
2041    }
2042    
2043    extern JSFunction* js_NewGCFunction(JSContext *cx, uintN flags)
2044    {
2045        return NewGCThing<JSFunction>(cx, flags);
2046    }
2047    
2048    extern JSXML* js_NewGCXML(JSContext *cx, uintN flags)
2049    {
2050        return NewGCThing<JSXML>(cx, flags);
2051    }
2052    
2053  static JSGCDoubleCell *  static JSGCDoubleCell *
2054  RefillDoubleFreeList(JSContext *cx)  RefillDoubleFreeList(JSContext *cx)
2055  {  {
# Line 2276  Line 2243 
2243      JSObject *&head = JS_TRACE_MONITOR(cx).reservedObjects;      JSObject *&head = JS_TRACE_MONITOR(cx).reservedObjects;
2244      size_t i = head ? JSVAL_TO_INT(head->fslots[1]) : 0;      size_t i = head ? JSVAL_TO_INT(head->fslots[1]) : 0;
2245      while (i < nobjects) {      while (i < nobjects) {
2246          JSObject *obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));          JSObject *obj = js_NewGCObject(cx, GCX_OBJECT);
2247          if (!obj)          if (!obj)
2248              return JS_FALSE;              return JS_FALSE;
2249          memset(obj, 0, sizeof(JSObject));          memset(obj, 0, sizeof(JSObject));
# Line 2292  Line 2259 
2259  }  }
2260  #endif  #endif
2261    
 JSBool  
 js_AddAsGCBytes(JSContext *cx, size_t sz)  
 {  
     JSRuntime *rt;  
   
     rt = cx->runtime;  
     if (rt->gcBytes >= rt->gcMaxBytes ||  
         sz > (size_t) (rt->gcMaxBytes - rt->gcBytes) ||  
         IsGCThresholdReached(rt)) {  
         if (JS_ON_TRACE(cx)) {  
             /*  
              * If we can't leave the trace, signal OOM condition, otherwise  
              * exit from trace and proceed with GC.  
              */  
             if (!js_CanLeaveTrace(cx)) {  
                 JS_UNLOCK_GC(rt);  
                 return JS_FALSE;  
             }  
             js_LeaveTrace(cx);  
         }  
         js_GC(cx, GC_LAST_DITCH);  
         if (rt->gcBytes >= rt->gcMaxBytes ||  
             sz > (size_t) (rt->gcMaxBytes - rt->gcBytes)) {  
             JS_UNLOCK_GC(rt);  
             JS_ReportOutOfMemory(cx);  
             return JS_FALSE;  
         }  
     }  
     rt->gcBytes += (uint32) sz;  
     return JS_TRUE;  
 }  
   
 void  
 js_RemoveAsGCBytes(JSRuntime *rt, size_t sz)  
 {  
     JS_ASSERT((size_t) rt->gcBytes >= sz);  
     rt->gcBytes -= (uint32) sz;  
 }  
   
2262  /*  /*
2263   * Shallow GC-things can be locked just by setting the GCF_LOCK bit, because   * Shallow GC-things can be locked just by setting the GCF_LOCK bit, because
2264   * they have no descendants to mark during the GC. Currently the optimization   * they have no descendants to mark during the GC. Currently the optimization
# Line 2340  Line 2268 
2268      ((flagp) &&                                                               \      ((flagp) &&                                                               \
2269       ((*(flagp) & GCF_TYPEMASK) >= GCX_EXTERNAL_STRING ||                     \       ((*(flagp) & GCF_TYPEMASK) >= GCX_EXTERNAL_STRING ||                     \
2270        ((*(flagp) & GCF_TYPEMASK) == GCX_STRING &&                             \        ((*(flagp) & GCF_TYPEMASK) == GCX_STRING &&                             \
2271         !JSSTRING_IS_DEPENDENT((JSString *) (thing)))))         !((JSString *) (thing))->isDependent())))
2272    
2273  /* This is compatible with JSDHashEntryStub. */  /* This is compatible with JSDHashEntryStub. */
2274  typedef struct JSGCLockHashEntry {  typedef struct JSGCLockHashEntry {
# Line 2447  Line 2375 
2375  JS_PUBLIC_API(void)  JS_PUBLIC_API(void)
2376  JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)  JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
2377  {  {
     JSObject *obj;  
     size_t nslots, i;  
     jsval v;  
     JSString *str;  
   
2378      switch (kind) {      switch (kind) {
2379        case JSTRACE_OBJECT:        case JSTRACE_OBJECT: {
2380          /* If obj has no map, it must be a newborn. */          /* If obj has no map, it must be a newborn. */
2381          obj = (JSObject *) thing;          JSObject *obj = (JSObject *) thing;
2382          if (!obj->map)          if (!obj->map)
2383              break;              break;
2384          if (obj->map->ops->trace) {          obj->map->ops->trace(trc, obj);
             obj->map->ops->trace(trc, obj);  
         } else {  
             nslots = STOBJ_NSLOTS(obj);  
             for (i = 0; i != nslots; ++i) {  
                 v = STOBJ_GET_SLOT(obj, i);  
                 if (JSVAL_IS_TRACEABLE(v)) {  
                     JS_SET_TRACING_INDEX(trc, "slot", i);  
                     JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v),  
                                   JSVAL_TRACE_KIND(v));  
                 }  
             }  
         }  
2385          break;          break;
2386          }
2387    
2388        case JSTRACE_STRING:        case JSTRACE_STRING: {
2389          str = (JSString *)thing;          JSString *str = (JSString *) thing;
2390          if (JSSTRING_IS_DEPENDENT(str))          if (str->isDependent())
2391              JS_CALL_STRING_TRACER(trc, JSSTRDEP_BASE(str), "base");              JS_CALL_STRING_TRACER(trc, str->dependentBase(), "base");
2392          break;          break;
2393          }
2394    
2395  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
2396        case JSTRACE_XML:        case JSTRACE_XML:
# Line 2694  Line 2607 
2607    
2608        case JSTRACE_STRING:        case JSTRACE_STRING:
2609          for (;;) {          for (;;) {
2610                if (JSString::isStatic(thing))
2611                    goto out;
2612              flagp = THING_TO_FLAGP(thing, sizeof(JSGCThing));              flagp = THING_TO_FLAGP(thing, sizeof(JSGCThing));
2613              JS_ASSERT((*flagp & GCF_FINAL) == 0);              JS_ASSERT((*flagp & GCF_FINAL) == 0);
2614              JS_ASSERT(kind == MapGCFlagsToTraceKind(*flagp));              JS_ASSERT(kind == MapGCFlagsToTraceKind(*flagp));
2615              if (!JSSTRING_IS_DEPENDENT((JSString *) thing)) {              if (!((JSString *) thing)->isDependent()) {
2616                  *flagp |= GCF_MARK;                  *flagp |= GCF_MARK;
2617                  goto out;                  goto out;
2618              }              }
2619              if (*flagp & GCF_MARK)              if (*flagp & GCF_MARK)
2620                  goto out;                  goto out;
2621              *flagp |= GCF_MARK;              *flagp |= GCF_MARK;
2622              thing = JSSTRDEP_BASE((JSString *) thing);              thing = ((JSString *) thing)->dependentBase();
2623          }          }
2624          /* NOTREACHED */          /* NOTREACHED */
2625      }      }
# Line 2795  Line 2710 
2710      jsval *rp = (jsval *)rhe->root;      jsval *rp = (jsval *)rhe->root;
2711      jsval v = *rp;      jsval v = *rp;
2712    
2713      /* Ignore null object and scalar values. */      /* Ignore null reference, scalar values, and static strings. */
2714      if (!JSVAL_IS_NULL(v) && JSVAL_IS_GCTHING(v)) {      if (!JSVAL_IS_NULL(v) &&
2715            JSVAL_IS_GCTHING(v) &&
2716            !JSString::isStatic(JSVAL_TO_GCTHING(v))) {
2717  #ifdef DEBUG  #ifdef DEBUG
2718          JSBool root_points_to_gcArenaList = JS_FALSE;          JSBool root_points_to_gcArenaList = JS_FALSE;
2719          jsuword thing = (jsuword) JSVAL_TO_GCTHING(v);          jsuword thing = (jsuword) JSVAL_TO_GCTHING(v);
# Line 2882  Line 2799 
2799      if (fp->callobj)      if (fp->callobj)
2800          JS_CALL_OBJECT_TRACER(trc, fp->callobj, "call");          JS_CALL_OBJECT_TRACER(trc, fp->callobj, "call");
2801      if (fp->argsobj)      if (fp->argsobj)
2802          JS_CALL_OBJECT_TRACER(trc, fp->argsobj, "arguments");          JS_CALL_OBJECT_TRACER(trc, JSVAL_TO_OBJECT(fp->argsobj), "arguments");
2803      if (fp->varobj)      if (fp->varobj)
2804          JS_CALL_OBJECT_TRACER(trc, fp->varobj, "variables");          JS_CALL_OBJECT_TRACER(trc, fp->varobj, "variables");
2805      if (fp->script) {      if (fp->script) {
# Line 2894  Line 2811 
2811               * Don't mark what has not been pushed yet, or what has been               * Don't mark what has not been pushed yet, or what has been
2812               * popped already.               * popped already.
2813               */               */
2814              if (fp->regs) {              if (fp->regs && fp->regs->sp) {
2815                  nslots = (uintN) (fp->regs->sp - fp->slots);                  nslots = (uintN) (fp->regs->sp - fp->slots);
2816                  JS_ASSERT(nslots >= fp->script->nfixed);                  JS_ASSERT(nslots >= fp->script->nfixed);
2817              } else {              } else {
# Line 2912  Line 2829 
2829                (fp->fun && JSFUN_THISP_FLAGS(fp->fun->flags)));                (fp->fun && JSFUN_THISP_FLAGS(fp->fun->flags)));
2830      JS_CALL_VALUE_TRACER(trc, (jsval)fp->thisp, "this");      JS_CALL_VALUE_TRACER(trc, (jsval)fp->thisp, "this");
2831    
     if (fp->callee)  
         JS_CALL_OBJECT_TRACER(trc, fp->callee, "callee");  
   
2832      if (fp->argv) {      if (fp->argv) {
2833            JS_CALL_VALUE_TRACER(trc, fp->argv[-2], "callee");
2834          nslots = fp->argc;          nslots = fp->argc;
2835          skip = 0;          skip = 0;
2836          if (fp->fun) {          if (fp->fun) {
# Line 2937  Line 2852 
2852          JS_CALL_OBJECT_TRACER(trc, fp->scopeChain, "scope chain");          JS_CALL_OBJECT_TRACER(trc, fp->scopeChain, "scope chain");
2853      if (fp->sharpArray)      if (fp->sharpArray)
2854          JS_CALL_OBJECT_TRACER(trc, fp->sharpArray, "sharp array");          JS_CALL_OBJECT_TRACER(trc, fp->sharpArray, "sharp array");
   
     if (fp->xmlNamespace)  
         JS_CALL_OBJECT_TRACER(trc, fp->xmlNamespace, "xmlNamespace");  
2855  }  }
2856    
2857  static void  static void
# Line 2999  Line 2911 
2911              }                                                                 \              }                                                                 \
2912          JS_END_MACRO          JS_END_MACRO
2913    
 #ifdef JS_THREADSAFE  
         js_RevokeGCLocalFreeLists(acx);  
 #endif  
   
2914          /*          /*
2915           * Release the stackPool's arenas if the stackPool has existed for           * Release the stackPool's arenas if the stackPool has existed for
2916           * longer than the limit specified by gcEmptyArenaPoolLifespan.           * longer than the limit specified by gcEmptyArenaPoolLifespan.
# Line 3088  Line 2996 
2996              tvr->u.trace(trc, tvr);              tvr->u.trace(trc, tvr);
2997              break;              break;
2998            case JSTVU_SPROP:            case JSTVU_SPROP:
2999              TRACE_SCOPE_PROPERTY(trc, tvr->u.sprop);              tvr->u.sprop->trace(trc);
3000              break;              break;
3001            case JSTVU_WEAK_ROOTS:            case JSTVU_WEAK_ROOTS:
3002              TraceWeakRoots(trc, tvr->u.weakRoots);              TraceWeakRoots(trc, tvr->u.weakRoots);
# Line 3099  Line 3007 
3007            case JSTVU_SCRIPT:            case JSTVU_SCRIPT:
3008              js_TraceScript(trc, tvr->u.script);              js_TraceScript(trc, tvr->u.script);
3009              break;              break;
3010              case JSTVU_ENUMERATOR:
3011                static_cast<JSAutoEnumStateRooter *>(tvr)->mark(trc);
3012                break;
3013            default:            default:
3014              JS_ASSERT(tvr->count >= 0);              JS_ASSERT(tvr->count >= 0);
3015              TRACE_JSVALS(trc, tvr->count, tvr->u.array, "tvr->u.array");              TRACE_JSVALS(trc, tvr->count, tvr->u.array, "tvr->u.array");
# Line 3111  Line 3022 
3022      js_TraceRegExpStatics(trc, acx);      js_TraceRegExpStatics(trc, acx);
3023    
3024  #ifdef JS_TRACER  #ifdef JS_TRACER
3025      if (acx->nativeVp)      InterpState* state = acx->interpState;
3026          TRACE_JSVALS(trc, acx->nativeVpLen, acx->nativeVp, "nativeVp");      while (state) {
3027            if (state->nativeVp)
3028                TRACE_JSVALS(trc, state->nativeVpLen, state->nativeVp, "nativeVp");
3029            state = state->prev;
3030        }
3031  #endif  #endif
3032  }  }
3033    
3034  #ifdef JS_TRACER  #ifdef JS_TRACER
3035    
3036  static void  static void
3037  MarkReservedObjects(JSTraceMonitor *tm)  MarkReservedGCThings(JSTraceMonitor *tm)
3038  {  {
3039      /* Keep the reserved objects. */      /* Keep reserved doubles. */
3040        for (jsval *ptr = tm->reservedDoublePool; ptr < tm->reservedDoublePoolPtr; ++ptr) {
3041            jsdouble* dp = JSVAL_TO_DOUBLE(*ptr);
3042            JS_ASSERT(js_GetGCThingTraceKind(dp) == JSTRACE_DOUBLE);
3043    
3044            JSGCArenaInfo *a = THING_TO_ARENA(dp);
3045            JS_ASSERT(!a->list);
3046            if (!a->u.hasMarkedDoubles) {
3047                ClearDoubleArenaFlags(a);
3048                a->u.hasMarkedDoubles = JS_TRUE;
3049            }
3050            jsuint index = DOUBLE_THING_TO_INDEX(dp);
3051            JS_SET_BIT(DOUBLE_ARENA_BITMAP(a), index);
3052        }
3053        /* Keep reserved objects. */
3054      for (JSObject *obj = tm->reservedObjects; obj; obj = JSVAL_TO_OBJECT(obj->fslots[0])) {      for (JSObject *obj = tm->reservedObjects; obj; obj = JSVAL_TO_OBJECT(obj->fslots[0])) {
3055          uint8 *flagp = GetGCThingFlags(obj);          uint8 *flagp = GetGCThingFlags(obj);
3056          JS_ASSERT((*flagp & GCF_TYPEMASK) == GCX_OBJECT);          JS_ASSERT((*flagp & GCF_TYPEMASK) == GCX_OBJECT);
# Line 3132  Line 3061 
3061    
3062  #ifdef JS_THREADSAFE  #ifdef JS_THREADSAFE
3063  static JSDHashOperator  static JSDHashOperator
3064  reserved_objects_marker(JSDHashTable *table, JSDHashEntryHdr *hdr,  reserved_gcthings_marker(JSDHashTable *table, JSDHashEntryHdr *hdr,
3065                          uint32, void *)                           uint32, void *)
3066  {  {
3067      JSThread *thread = ((JSThreadsHashEntry *) hdr)->thread;      JSThread *thread = ((JSThreadsHashEntry *) hdr)->thread;
3068    
3069      MarkReservedObjects(&thread->data.traceMonitor);      MarkReservedGCThings(&thread->data.traceMonitor);
3070      return JS_DHASH_NEXT;      return JS_DHASH_NEXT;
3071  }  }
3072  #endif  #endif
# Line 3154  Line 3083 
3083      if (rt->gcLocksHash)      if (rt->gcLocksHash)
3084          JS_DHashTableEnumerate(rt->gcLocksHash, gc_lock_traversal, trc);          JS_DHashTableEnumerate(rt->gcLocksHash, gc_lock_traversal, trc);
3085      js_TraceAtomState(trc, allAtoms);      js_TraceAtomState(trc, allAtoms);
     js_TraceNativeEnumerators(trc);  
3086      js_TraceRuntimeNumberState(trc);      js_TraceRuntimeNumberState(trc);
3087    
3088      iter = NULL;      iter = NULL;
3089      while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)      while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
3090          js_TraceContext(trc, acx);          js_TraceContext(trc, acx);
3091    
3092        js_TraceThreads(rt, trc);
3093    
3094      if (rt->gcExtraRootsTraceOp)      if (rt->gcExtraRootsTraceOp)
3095          rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData);          rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData);
3096    
# Line 3170  Line 3100 
3100              JS_CALL_OBJECT_TRACER(trc, rt->builtinFunctions[i], "builtin function");              JS_CALL_OBJECT_TRACER(trc, rt->builtinFunctions[i], "builtin function");
3101      }      }
3102    
3103      /* Mark the reserved objects unless we are shutting down. */      /* Mark reserved gcthings unless we are shutting down. */
3104      if (IS_GC_MARKING_TRACER(trc) && rt->state != JSRTS_LANDING) {      if (IS_GC_MARKING_TRACER(trc) && rt->state != JSRTS_LANDING) {
3105  #ifdef JS_THREADSAFE  #ifdef JS_THREADSAFE
3106          JS_DHashTableEnumerate(&rt->threads, reserved_objects_marker, NULL);          JS_DHashTableEnumerate(&rt->threads, reserved_gcthings_marker, NULL);
3107  #else  #else
3108          MarkReservedObjects(&rt->threadData.traceMonitor);          MarkReservedGCThings(&rt->threadData.traceMonitor);
3109  #endif  #endif
3110      }      }
3111    
# Line 3220  Line 3150 
3150    
3151      pobj = ssr->pobj;      pobj = ssr->pobj;
3152      if (slot == JSSLOT_PROTO) {      if (slot == JSSLOT_PROTO) {
3153          STOBJ_SET_PROTO(obj, pobj);          obj->setProto(pobj);
3154      } else {      } else {
3155          JS_ASSERT(slot == JSSLOT_PARENT);          JS_ASSERT(slot == JSSLOT_PARENT);
3156          STOBJ_SET_PARENT(obj, pobj);          obj->setParent(pobj);
3157      }      }
3158  }  }
3159    
# Line 3242  Line 3172 
3172      }      }
3173  }  }
3174    
3175    static void
3176    FinalizeObject(JSContext *cx, JSObject *obj)
3177    {
3178        /* Cope with stillborn objects that have no map. */
3179        if (!obj->map)
3180            return;
3181    
3182        if (JS_UNLIKELY(cx->debugHooks->objectHook != NULL)) {
3183            cx->debugHooks->objectHook(cx, obj, JS_FALSE,
3184                                       cx->debugHooks->objectHookData);
3185        }
3186    
3187        /* Finalize obj first, in case it needs map and slots. */
3188        JSClass *clasp = STOBJ_GET_CLASS(obj);
3189        if (clasp->finalize)
3190            clasp->finalize(cx, obj);
3191    
3192    #ifdef INCLUDE_MOZILLA_DTRACE
3193        if (JAVASCRIPT_OBJECT_FINALIZE_ENABLED())
3194            jsdtrace_object_finalize(obj);
3195    #endif
3196    
3197        if (JS_LIKELY(OBJ_IS_NATIVE(obj)))
3198            OBJ_SCOPE(obj)->drop(cx, obj);
3199        js_FreeSlots(cx, obj);
3200    }
3201    
3202    static JSStringFinalizeOp str_finalizers[GCX_NTYPES - GCX_EXTERNAL_STRING] = {
3203        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
3204    };
3205    
3206    intN
3207    js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop,
3208                                     JSStringFinalizeOp newop)
3209    {
3210        uintN i;
3211    
3212        for (i = 0; i != JS_ARRAY_LENGTH(str_finalizers); i++) {
3213            if (str_finalizers[i] == oldop) {
3214                str_finalizers[i] = newop;
3215                return (intN) i;
3216            }
3217        }
3218        return -1;
3219    }
3220    
3221    /*
3222     * cx is NULL when we are called from js_FinishAtomState to force the
3223     * finalization of the permanently interned strings.
3224     */
3225    void
3226    js_FinalizeStringRT(JSRuntime *rt, JSString *str, intN type, JSContext *cx)
3227    {
3228        jschar *chars;
3229        JSBool valid;
3230        JSStringFinalizeOp finalizer;
3231    
3232        JS_RUNTIME_UNMETER(rt, liveStrings);
3233        JS_ASSERT(!JSString::isStatic(str));
3234        if (str->isDependent()) {
3235            /* A dependent string can not be external and must be valid. */
3236            JS_ASSERT(type < 0);
3237            JS_ASSERT(str->dependentBase());
3238            JS_RUNTIME_UNMETER(rt, liveDependentStrings);
3239            valid = JS_TRUE;
3240        } else {
3241            /* A stillborn string has null chars, so is not valid. */
3242            chars = str->flatChars();
3243            valid = (chars != NULL);
3244            if (valid) {
3245                if (type < 0) {
3246                    if (cx)
3247                        cx->free(chars);
3248                    else
3249                        rt->free(chars);
3250                } else {
3251                    JS_ASSERT((uintN) type < JS_ARRAY_LENGTH(str_finalizers));
3252                    finalizer = str_finalizers[type];
3253                    if (finalizer) {
3254                        /*
3255                         * Assume that the finalizer for the permanently interned
3256                         * string knows how to deal with null context.
3257                         */
3258                        finalizer(cx, str);
3259                    }
3260                }
3261            }
3262        }
3263        if (valid && str->isDeflated())
3264            js_PurgeDeflatedStringCache(rt, str);
3265    }
3266    
3267  /*  /*
3268   * The gckind flag bit GC_LOCK_HELD indicates a call from js_NewGCThing with   * The gckind flag bit GC_LOCK_HELD indicates a call from js_NewGCThing with
3269   * rt->gcLock already held, so the lock should be kept on return.   * rt->gcLock already held, so the lock should be kept on return.
# Line 3460  Line 3482 
3482  #ifdef JS_TRACER  #ifdef JS_TRACER
3483      js_PurgeJITOracle();      js_PurgeJITOracle();
3484  #endif  #endif
     js_PurgeThreads(cx);  
3485    
3486    restart:    restart:
3487      rt->gcNumber++;      rt->gcNumber++;
# Line 3472  Line 3493 
3493       * Same for the protoHazardShape proxy-shape standing in for all object       * Same for the protoHazardShape proxy-shape standing in for all object
3494       * prototypes having readonly or setter properties.       * prototypes having readonly or setter properties.
3495       */       */
3496      rt->shapeGen = 0;      if (rt->shapeGen & SHAPE_OVERFLOW_BIT
3497      rt->protoHazardShape = 0;  #ifdef JS_GC_ZEAL
3498            || rt->gcZeal >= 1
3499    #endif
3500            ) {
3501            rt->gcRegenShapes = true;
3502            rt->gcRegenShapesScopeFlag ^= JSScope::SHAPE_REGEN;
3503            rt->shapeGen = 0;
3504            rt->protoHazardShape = 0;
3505        }
3506    
3507        js_PurgeThreads(cx);
3508    #ifdef JS_TRACER
3509        if (gckind == GC_LAST_CONTEXT) {
3510            /* Clear builtin functions, which are recreated on demand. */
3511            memset(rt->builtinFunctions, 0, sizeof rt->builtinFunctions);
3512        }
3513    #endif
3514    
3515      /*      /*
3516       * Mark phase.       * Mark phase.
# Line 3505  Line 3542 
3542    
3543      rt->gcMarkingTracer = NULL;      rt->gcMarkingTracer = NULL;
3544    
3545    #ifdef JS_THREADSAFE
3546        cx->createDeallocatorTask();
3547    #endif
3548    
3549      /*      /*
3550       * Sweep phase.       * Sweep phase.
3551       *       *
# Line 3578  Line 3619 
3619                          type = flags & GCF_TYPEMASK;                          type = flags & GCF_TYPEMASK;
3620                          switch (type) {                          switch (type) {
3621                            case GCX_OBJECT:                            case GCX_OBJECT:
3622                              js_FinalizeObject(cx, (JSObject *) thing);                              FinalizeObject(cx, (JSObject *) thing);
                             break;  
                           case GCX_DOUBLE:  
                             /* Do nothing. */  
3623                              break;                              break;
3624  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
3625                            case GCX_XML:                            case GCX_XML:
# Line 3615  Line 3653 
3653                   */                   */
3654                  freeList = arenaList->freeList;                  freeList = arenaList->freeList;
3655                  if (a == arenaList->last)                  if (a == arenaList->last)
3656                      arenaList->lastCount = (uint16) indexLimit;                      arenaList->lastCount = indexLimit;
3657                  *ap = a->prev;                  *ap = a->prev;
3658                  a->prev = emptyArenas;                  a->prev = emptyArenas;
3659                  emptyArenas = a;                  emptyArenas = a;
# Line 3639  Line 3677 
3677                                 nlivearenas, nkilledarenas, nthings));                                 nlivearenas, nkilledarenas, nthings));
3678      }      }
3679    
 #ifdef JS_THREADSAFE  
     /*  
      * Release all but two free list sets to avoid allocating a new set in  
      * js_NewGCThing.  
      */  
     TrimGCFreeListsPool(rt, 2);  
 #endif  
   
3680      ap = &rt->gcDoubleArenaList.first;      ap = &rt->gcDoubleArenaList.first;
3681      METER((nlivearenas = 0, nkilledarenas = 0, nthings = 0));      METER((nlivearenas = 0, nkilledarenas = 0, nthings = 0));
3682      while ((a = *ap) != NULL) {      while ((a = *ap) != NULL) {
# Line 3694  Line 3724 
3724       */       */
3725      DestroyGCArenas(rt, emptyArenas);      DestroyGCArenas(rt, emptyArenas);
3726    
3727    #ifdef JS_THREADSAFE
3728        cx->submitDeallocatorTask();
3729    #endif
3730    
3731      if (rt->gcCallback)      if (rt->gcCallback)
3732          (void) rt->gcCallback(cx, JSGC_FINALIZE_END);          (void) rt->gcCallback(cx, JSGC_FINALIZE_END);
3733  #ifdef DEBUG_srcnotesize  #ifdef DEBUG_srcnotesize
# Line 3748  Line 3782 
3782          goto restart;          goto restart;
3783      }      }
3784    
3785      rt->gcLastBytes = rt->gcBytes;      rt->setGCLastBytes(rt->gcBytes);
3786    done_running:    done_running:
3787      rt->gcLevel = 0;      rt->gcLevel = 0;
3788      rt->gcRunning = JS_FALSE;      rt->gcRunning = rt->gcRegenShapes = false;
3789    
3790  #ifdef JS_THREADSAFE  #ifdef JS_THREADSAFE
3791      rt->gcThread = NULL;      rt->gcThread = NULL;
# Line 3800  Line 3834 
3834          }          }
3835      }      }
3836  }  }
   
 void  
 js_UpdateMallocCounter(JSContext *cx, size_t nbytes)  
 {  
     uint32 *pbytes, bytes;  
   
 #ifdef JS_THREADSAFE  
     pbytes = &cx->thread->gcMallocBytes;  
 #else  
     pbytes = &cx->runtime->gcMallocBytes;  
 #endif  
     bytes = *pbytes;  
     *pbytes = ((uint32)-1 - bytes <= nbytes) ? (uint32)-1 : bytes + nbytes;  
 }  

Legend:
Removed from v.506  
changed lines
  Added in v.507

  ViewVC Help
Powered by ViewVC 1.1.24