Ignore:
Timestamp:
Mar 21, 2002, 4:31:57 PM (23 years ago)
Author:
mjs
Message:

Merged changes from LABYRINTH_KDE_3_MERGE branch.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/collector.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    34 *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1618 *  License along with this library; if not, write to the Free Software
    1719 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     20 *
     21 *  $Id$
    1822 */
    1923
    2024#include "collector.h"
    21 #include "object.h"
    2225#include "internal.h"
    2326
     
    2528#include <string.h>
    2629#include <assert.h>
     30#ifdef KJS_DEBUG_MEM
     31#include <typeinfo>
     32#endif
    2733
    2834namespace KJS {
     
    6268unsigned long Collector::filled = 0;
    6369unsigned long Collector::softLimit = KJS_MEM_INCREMENT;
     70
     71unsigned long Collector::timesFilled = 0;
     72unsigned long Collector::increaseLimitAt = 1;
     73
     74bool Collector::memLimitReached = false;
     75
    6476#ifdef KJS_DEBUG_MEM
    6577bool Collector::collecting = false;
     
    7183    return 0L;
    7284
     85  // Try and deal with memory requirements in a scalable way. Simple scripts
     86  // should only require small amounts of memory, but for complex scripts we don't
     87  // want to end up running the garbage collector hundreds of times a second.
    7388  if (filled >= softLimit) {
     89    timesFilled++;
    7490    collect();
    75     if (filled >= softLimit && softLimit < KJS_MEM_LIMIT) // we are actually using all this memory
     91
     92    if (filled >= softLimit && softLimit < KJS_MEM_LIMIT) {
     93      // Even after collection we are still using more than the limit, so increase
     94      // the limit
    7695      softLimit *= 2;
     96    }
     97    else if (timesFilled == increaseLimitAt && increaseLimitAt < 128) {
     98      // The allowed memory limit keeps getting reached (lots of objects created
     99      // and deleted). Increase it a bit so GC gets run less often.
     100      timesFilled = 0;
     101      softLimit *= 2;
     102      increaseLimitAt *= 2;
     103    }
    77104  }
    78105
    79106  void *m = malloc(s);
    80 
    81   // hack to ensure obj is protected from GC before any constructors are run
    82   // (prev = marked, next = gcallowed)
    83   static_cast<Imp*>(m)->prev = 0;
    84   static_cast<Imp*>(m)->next = 0;
     107#ifdef KJS_DEBUG_MEM
     108  //fprintf( stderr, "allocate: size=%d valueimp=%p\n",s,m);
     109#endif
     110
     111  // VI_CREATED and VI_GCALLOWED being unset ensure that value
     112  // is protected from GC before any constructors are run
     113  static_cast<ValueImp*>(m)->_flags = 0;
    85114
    86115  if (!root) {
     
    99128  if (block->filled >= block->size) {
    100129#ifdef KJS_DEBUG_MEM
    101     printf("allocating new block of size %d\n", block->size);
     130    //fprintf( stderr, "allocating new block of size %d\n", block->size);
    102131#endif
    103132    CollectorBlock *tmp = new CollectorBlock(BlockSize);
     
    116145
    117146  if (softLimit >= KJS_MEM_LIMIT) {
    118       KJScriptImp::setException("Out of memory");
     147    memLimitReached = true;
     148    fprintf(stderr,"Out of memory");
    119149  }
    120150
     
    125155 * Mark-sweep garbage collection.
    126156 */
    127 void Collector::collect()
    128 {
    129 #ifdef KJS_DEBUG_MEM
    130   printf("collecting %d objects total\n", Imp::count);
    131   collecting = true;
    132 #endif
    133 
    134   // MARK: first set all ref counts to 0 ....
     157bool Collector::collect()
     158{
     159#ifdef KJS_DEBUG_MEM
     160  fprintf(stderr,"Collector::collect()\n");
     161#endif
     162  bool deleted = false;
     163  // MARK: first unmark everything
    135164  CollectorBlock *block = root;
    136165  while (block) {
    137 #ifdef KJS_DEBUG_MEM
    138     printf("cleaning block filled %d out of %d\n", block->filled, block->size);
    139 #endif
    140     Imp **r = (Imp**)block->mem;
     166    ValueImp **r = (ValueImp**)block->mem;
    141167    assert(r);
    142168    for (int i = 0; i < block->size; i++, r++)
    143169      if (*r) {
    144         (*r)->setMarked(false);
    145       }
    146     block = block->next;
    147   }
    148 
    149   // ... increase counter for all referenced objects recursively
     170        (*r)->_flags &= ~ValueImp::VI_MARKED;
     171      }
     172    block = block->next;
     173  }
     174
     175  // mark all referenced objects recursively
    150176  // starting out from the set of root objects
    151   if (KJScriptImp::hook) {
    152     KJScriptImp *scr = KJScriptImp::hook;
     177  if (InterpreterImp::s_hook) {
     178    InterpreterImp *scr = InterpreterImp::s_hook;
    153179    do {
     180      //fprintf( stderr, "Collector marking interpreter %p\n",(void*)scr);
    154181      scr->mark();
    155182      scr = scr->next;
    156     } while (scr != KJScriptImp::hook);
     183    } while (scr != InterpreterImp::s_hook);
    157184  }
    158185
     
    160187  block = root;
    161188  while (block) {
    162     Imp **r = (Imp**)block->mem;
     189    ValueImp **r = (ValueImp**)block->mem;
    163190    assert(r);
    164191    for (int i = 0; i < block->size; i++, r++)
    165       if (*r && (*r)->created() && ((*r)->refcount || !(*r)->gcAllowed()) && !(*r)->marked())
    166         (*r)->mark();
     192    {
     193      ValueImp *imp = (*r);
     194      // Check for created=true, marked=false and (gcallowed=false or refcount>0)
     195      if (imp &&
     196          (imp->_flags & (ValueImp::VI_CREATED|ValueImp::VI_MARKED)) == ValueImp::VI_CREATED &&
     197          ( (imp->_flags & ValueImp::VI_GCALLOWED) == 0 || imp->refcount ) ) {
     198        //fprintf( stderr, "Collector marking imp=%p\n",(void*)imp);
     199        imp->mark();
     200      }
     201    }
    167202    block = block->next;
    168203  }
     
    171206  block = root;
    172207  while (block) {
    173     Imp **r = (Imp**)block->mem;
     208    ValueImp **r = (ValueImp**)block->mem;
    174209    int del = 0;
    175210    for (int i = 0; i < block->size; i++, r++) {
    176       if (*r && ((*r)->refcount == 0) && !(*r)->marked() && (*r)->gcAllowed()) {
    177         // emulate destructing part of 'operator delete()'
    178         (*r)->~Imp();
    179         free(*r);
    180         *r = 0L;
    181         del++;
     211      ValueImp *imp = (*r);
     212      // Can delete if refcount==0, created==true, gcAllowed==true, and marked==false
     213      // Make sure to update the test if you add more bits to _flags.
     214      if (imp &&
     215          !imp->refcount && imp->_flags == (ValueImp::VI_GCALLOWED | ValueImp::VI_CREATED)) {
     216        // emulate destructing part of 'operator delete()'
     217        //fprintf( stderr, "Collector::deleting ValueImp %p (%s)\n", (void*)imp, typeid(*imp).name());
     218        imp->~ValueImp();
     219        free(imp);
     220        *r = 0L;
     221        del++;
    182222      }
    183223    }
     
    185225    block->filled -= del;
    186226    block = block->next;
    187   }
    188 
    189   // delete the emtpy containers
     227    if (del)
     228      deleted = true;
     229  }
     230
     231  // delete the empty containers
    190232  block = root;
    191233  while (block) {
     
    193235    if (block->filled == 0) {
    194236      if (block->prev)
    195         block->prev->next = next;
     237        block->prev->next = next;
    196238      if (block == root)
    197         root = next;
     239        root = next;
    198240      if (next)
    199         next->prev = block->prev;
     241        next->prev = block->prev;
    200242      if (block == currentBlock) // we don't want a dangling pointer
    201         currentBlock = 0L;
     243        currentBlock = 0L;
    202244      assert(block != root);
    203245      delete block;
     
    205247    block = next;
    206248  }
    207 
    208 #ifdef KJS_DEBUG_MEM
    209   collecting = false;
    210 #endif
    211 }
     249#if 0
     250  // This is useful to track down memory leaks
     251  static int s_count = 0;
     252  fprintf(stderr, "Collector done (was run %d)\n",s_count);
     253  if (s_count++ % 50 == 2)
     254    finalCheck();
     255#endif
     256  return deleted;
     257}
     258
     259#ifdef KJS_DEBUG_MEM
     260void Collector::finalCheck()
     261{
     262  CollectorBlock *block = root;
     263  while (block) {
     264    ValueImp **r = (ValueImp**)block->mem;
     265    for (int i = 0; i < block->size; i++, r++) {
     266      if (*r ) {
     267        fprintf( stderr, "Collector::finalCheck() still having ValueImp %p (%s)  [marked:%d gcAllowed:%d created:%d refcount:%d]\n",
     268                 (void*)(*r), typeid( **r ).name(),
     269                 (bool)((*r)->_flags & ValueImp::VI_MARKED),
     270                 (bool)((*r)->_flags & ValueImp::VI_GCALLOWED),
     271                 (bool)((*r)->_flags & ValueImp::VI_CREATED),
     272                 (*r)->refcount);
     273      }
     274    }
     275    block = block->next;
     276  }
     277}
     278#endif
Note: See TracChangeset for help on using the changeset viewer.