Changeset 10179 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
Aug 14, 2005, 9:17:11 AM (20 years ago)
Author:
darin
Message:

Reviewed by Maciej.

seems to give about 2% on iBench JavaScript

  • kjs/collector.cpp: (KJS::Collector::allocate): Use local variables to shadow globals instead of repeatedly going at global variables. Tighten up loop implementations to make the common case fast. (KJS::Collector::markStackObjectsConservatively): Use local variables to shadow globals. Used a goto to eliminate a boolean since it was showing up in the profile. (KJS::Collector::markProtectedObjects): Iterate through the table using pointer rather than an index since the profile showed that generating better code. (KJS::Collector::collect): Added a special case for blocks where all cells are used, Use local variables to shadow globals. Eliminated a boolean by computing it another way (checking to see if the number of live objects changed). Also used local variables to shadow fields in the current cell when sweeping. (KJS::Collector::numReferencedObjects): Use AllocatedValueImp instead of ValueImp in one place -- means we get faster versions of various functions that don't worry about SimpleNumber. (KJS::className): Ditto. (KJS::Collector::rootObjectClasses): Ditto.
Location:
trunk/JavaScriptCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r10178 r10179  
     12005-08-14  Darin Adler  <[email protected]>
     2
     3        Reviewed by Maciej.
     4
     5        - fixed http://bugzilla.opendarwin.org/show_bug.cgi?id=4416
     6          speed up JavaScript with some improvements to the garbage collector
     7
     8        seems to give about 2% on iBench JavaScript
     9
     10        * kjs/collector.cpp:
     11        (KJS::Collector::allocate): Use local variables to shadow globals instead of repeatedly
     12        going at global variables. Tighten up loop implementations to make the common case fast.
     13        (KJS::Collector::markStackObjectsConservatively): Use local variables to shadow globals.
     14        Used a goto to eliminate a boolean since it was showing up in the profile.
     15        (KJS::Collector::markProtectedObjects): Iterate through the table using pointer rather
     16        than an index since the profile showed that generating better code.
     17        (KJS::Collector::collect): Added a special case for blocks where all cells are used,
     18        Use local variables to shadow globals. Eliminated a boolean by computing it another
     19        way (checking to see if the number of live objects changed). Also used local variables
     20        to shadow fields in the current cell when sweeping.
     21        (KJS::Collector::numReferencedObjects): Use AllocatedValueImp instead of ValueImp
     22        in one place -- means we get faster versions of various functions that don't worry
     23        about SimpleNumber.
     24        (KJS::className): Ditto.
     25        (KJS::Collector::rootObjectClasses): Ditto.
     26
    1272005-08-14  Darin Adler  <[email protected]>
    228
  • trunk/JavaScriptCore/kjs/collector.cpp

    r10084 r10179  
    105105  if (s > static_cast<size_t>(CELL_SIZE)) {
    106106    // oversize allocator
    107     if (heap.usedOversizeCells == heap.numOversizeCells) {
    108       heap.numOversizeCells = max(MIN_ARRAY_SIZE, heap.numOversizeCells * GROWTH_FACTOR);
    109       heap.oversizeCells = (CollectorCell **)kjs_fast_realloc(heap.oversizeCells, heap.numOversizeCells * sizeof(CollectorCell *));
     107
     108    int usedOversizeCells = heap.usedOversizeCells;
     109    int numOversizeCells = heap.numOversizeCells;
     110
     111    if (usedOversizeCells == numOversizeCells) {
     112      numOversizeCells = max(MIN_ARRAY_SIZE, numOversizeCells * GROWTH_FACTOR);
     113      heap.numOversizeCells = numOversizeCells;
     114      heap.oversizeCells = static_cast<CollectorCell **>(kjs_fast_realloc(heap.oversizeCells, numOversizeCells * sizeof(CollectorCell *)));
    110115    }
    111116   
    112117    void *newCell = kjs_fast_malloc(s);
    113     heap.oversizeCells[heap.usedOversizeCells] = (CollectorCell *)newCell;
    114     heap.usedOversizeCells++;
     118    heap.oversizeCells[usedOversizeCells] = static_cast<CollectorCell *>(newCell);
     119    heap.usedOversizeCells = usedOversizeCells + 1;
    115120    heap.numLiveObjects = numLiveObjects + 1;
    116121
     
    120125  // slab allocator
    121126 
    122   CollectorBlock *targetBlock = NULL;
    123  
    124   int i;
    125   for (i = heap.firstBlockWithPossibleSpace; i < heap.usedBlocks; i++) {
    126     if (heap.blocks[i]->usedCells < CELLS_PER_BLOCK) {
     127  int usedBlocks = heap.usedBlocks;
     128
     129  int i = heap.firstBlockWithPossibleSpace;
     130  CollectorBlock *targetBlock;
     131  int targetBlockUsedCells;
     132  if (i != usedBlocks) {
     133    targetBlock = heap.blocks[i];
     134    targetBlockUsedCells = targetBlock->usedCells;
     135    assert(targetBlockUsedCells <= CELLS_PER_BLOCK);
     136    while (targetBlockUsedCells == CELLS_PER_BLOCK) {
     137      if (++i == usedBlocks)
     138        goto allocateNewBlock;
    127139      targetBlock = heap.blocks[i];
    128       break;
    129     }
    130   }
    131 
    132   heap.firstBlockWithPossibleSpace = i;
    133  
    134   if (targetBlock == NULL) {
     140      targetBlockUsedCells = targetBlock->usedCells;
     141      assert(targetBlockUsedCells <= CELLS_PER_BLOCK);
     142    }
     143    heap.firstBlockWithPossibleSpace = i;
     144  } else {
     145allocateNewBlock:
    135146    // didn't find one, need to allocate a new block
    136    
    137     if (heap.usedBlocks == heap.numBlocks) {
    138       heap.numBlocks = max(MIN_ARRAY_SIZE, heap.numBlocks * GROWTH_FACTOR);
    139       heap.blocks = (CollectorBlock **)kjs_fast_realloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock *));
    140     }
    141    
    142     targetBlock = (CollectorBlock *)kjs_fast_calloc(1, sizeof(CollectorBlock));
     147
     148    int numBlocks = heap.numBlocks;
     149    if (usedBlocks == heap.numBlocks) {
     150      numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR);
     151      heap.numBlocks = numBlocks;
     152      heap.blocks = static_cast<CollectorBlock **>(kjs_fast_realloc(heap.blocks, numBlocks * sizeof(CollectorBlock *)));
     153    }
     154
     155    targetBlock = static_cast<CollectorBlock *>(kjs_fast_calloc(1, sizeof(CollectorBlock)));
    143156    targetBlock->freeList = targetBlock->cells;
    144     heap.blocks[heap.usedBlocks] = targetBlock;
    145     heap.usedBlocks++;
     157    targetBlockUsedCells = 0;
     158    heap.blocks[usedBlocks] = targetBlock;
     159    heap.usedBlocks = usedBlocks + 1;
     160    heap.firstBlockWithPossibleSpace = usedBlocks;
    146161  }
    147162 
     
    153168  targetBlock->freeList = reinterpret_cast<CollectorCell *>(reinterpret_cast<char *>(newCell + 1) + newCell->u.freeCell.next);
    154169
    155   targetBlock->usedCells++;
     170  targetBlock->usedCells = targetBlockUsedCells + 1;
    156171  heap.numLiveObjects = numLiveObjects + 1;
    157172
     
    228243  char **e = (char **)end;
    229244 
     245  int usedBlocks = heap.usedBlocks;
     246  CollectorBlock **blocks = heap.blocks;
     247  int usedOversizeCells = heap.usedOversizeCells;
     248  CollectorCell **oversizeCells = heap.oversizeCells;
     249
     250  const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
     251
    230252  while (p != e) {
    231253    char *x = *p++;
    232254    if (IS_CELL_ALIGNED(x) && x) {
    233       bool good = false;
    234       for (int block = 0; block < heap.usedBlocks; block++) {
    235         size_t offset = x - (char *)heap.blocks[block];
    236         const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
    237         if (offset <= lastCellOffset && offset % sizeof(CollectorCell) == 0) {
    238           good = true;
    239           break;
    240         }
    241       }
    242      
    243       if (!good) {
    244         int n = heap.usedOversizeCells;
    245         for (int i = 0; i != n; i++) {
    246           if (x == (char *)heap.oversizeCells[i]) {
    247             good = true;
    248             break;
    249           }
    250         }
    251       }
    252      
    253       if (good && ((CollectorCell *)x)->u.freeCell.zeroIfFree != 0) {
    254         AllocatedValueImp *imp = (AllocatedValueImp *)x;
    255         if (!imp->marked())
    256           imp->mark();
     255      for (int block = 0; block < usedBlocks; block++) {
     256        size_t offset = x - reinterpret_cast<char *>(blocks[block]);
     257        if (offset <= lastCellOffset && offset % sizeof(CollectorCell) == 0)
     258          goto gotGoodPointer;
     259      }
     260      for (int i = 0; i != usedOversizeCells; i++)
     261        if (x == reinterpret_cast<char *>(oversizeCells[i]))
     262          goto gotGoodPointer;
     263      continue;
     264
     265gotGoodPointer:
     266      if (((CollectorCell *)x)->u.freeCell.zeroIfFree != 0) {
     267        AllocatedValueImp *imp = reinterpret_cast<AllocatedValueImp *>(x);
     268        if (!imp->marked())
     269          imp->mark();
    257270      }
    258271    }
     
    324337void Collector::markProtectedObjects()
    325338{
    326   int size = ProtectedValues::_tableSize;
    327   ProtectedValues::KeyValue *table = ProtectedValues::_table;
    328   for (int i = 0; i < size; i++) {
    329     ValueImp *val = table[i].key;
     339  typedef ProtectedValues::KeyValue Entry;
     340  Entry *table = ProtectedValues::_table;
     341  Entry *end = table + ProtectedValues::_tableSize;
     342  for (Entry *entry = table; entry != end; ++entry) {
     343    AllocatedValueImp *val = entry->key;
    330344    if (val && !val->marked()) {
    331345      val->mark();
     
    337351{
    338352  assert(Interpreter::lockCount() > 0);
    339 
    340   bool deleted = false;
    341353
    342354  if (InterpreterImp::s_hook) {
     
    363375    CollectorBlock *curBlock = heap.blocks[block];
    364376
    365     int minimumCellsToProcess = curBlock->usedCells;
    366 
    367     for (int i = 0; i < CELLS_PER_BLOCK; i++) {
    368       if (minimumCellsToProcess < i) {
    369         goto skip_block_sweep;
    370       }
    371 
    372       CollectorCell *cell = curBlock->cells + i;
    373       AllocatedValueImp *imp = reinterpret_cast<AllocatedValueImp *>(cell);
    374 
    375       if (cell->u.freeCell.zeroIfFree != 0) {
    376         if (!imp->m_marked)
    377         {
    378           //fprintf(stderr, "Collector::deleting AllocatedValueImp %p (%s)\n", imp, className(imp));
    379           // emulate destructing part of 'operator delete()'
    380           imp->~AllocatedValueImp();
    381           curBlock->usedCells--;
    382           numLiveObjects--;
    383           deleted = true;
    384 
    385           // put it on the free list
    386           cell->u.freeCell.zeroIfFree = 0;
    387           cell->u.freeCell.next = reinterpret_cast<char *>(curBlock->freeList) - reinterpret_cast<char *>(cell + 1);
    388           curBlock->freeList = cell;
    389 
    390         } else {
    391           imp->m_marked = false;
    392         }
    393       } else {
    394         minimumCellsToProcess++;
    395       }
    396     }
    397 
    398   skip_block_sweep:
    399 
    400     if (heap.blocks[block]->usedCells == 0) {
     377    int usedCells = curBlock->usedCells;
     378    CollectorCell *freeList = curBlock->freeList;
     379
     380    if (usedCells == CELLS_PER_BLOCK) {
     381      // special case with a block where all cells are used -- testing indicates this happens often
     382      for (int i = 0; i < CELLS_PER_BLOCK; i++) {
     383        CollectorCell *cell = curBlock->cells + i;
     384        AllocatedValueImp *imp = reinterpret_cast<AllocatedValueImp *>(cell);
     385        if (imp->m_marked) {
     386          imp->m_marked = false;
     387        } else {
     388          imp->~AllocatedValueImp();
     389          --usedCells;
     390          --numLiveObjects;
     391
     392          // put cell on the free list
     393          cell->u.freeCell.zeroIfFree = 0;
     394          cell->u.freeCell.next = reinterpret_cast<char *>(freeList) - reinterpret_cast<char *>(cell + 1);
     395          freeList = cell;
     396        }
     397      }
     398    } else {
     399      int minimumCellsToProcess = usedCells;
     400      for (int i = 0; i < minimumCellsToProcess; i++) {
     401        CollectorCell *cell = curBlock->cells + i;
     402        if (cell->u.freeCell.zeroIfFree == 0) {
     403          ++minimumCellsToProcess;
     404        } else {
     405          AllocatedValueImp *imp = reinterpret_cast<AllocatedValueImp *>(cell);
     406          if (imp->m_marked) {
     407            imp->m_marked = false;
     408          } else {
     409            imp->~AllocatedValueImp();
     410            --usedCells;
     411            --numLiveObjects;
     412
     413            // put cell on the free list
     414            cell->u.freeCell.zeroIfFree = 0;
     415            cell->u.freeCell.next = reinterpret_cast<char *>(freeList) - reinterpret_cast<char *>(cell + 1);
     416            freeList = cell;
     417          }
     418        }
     419      }
     420    }
     421   
     422    curBlock->usedCells = usedCells;
     423    curBlock->freeList = freeList;
     424
     425    if (usedCells == 0) {
    401426      emptyBlocks++;
    402427      if (emptyBlocks > SPARE_EMPTY_BLOCKS) {
    403428#if !DEBUG_COLLECTOR
    404         kjs_fast_free(heap.blocks[block]);
     429        kjs_fast_free(curBlock);
    405430#endif
    406         // swap with the last block so we compact as we go
    407         heap.blocks[block] = heap.blocks[heap.usedBlocks - 1];
    408         heap.usedBlocks--;
    409         block--; // Don't move forward a step in this case
    410 
    411         if (heap.numBlocks > MIN_ARRAY_SIZE && heap.usedBlocks < heap.numBlocks / LOW_WATER_FACTOR) {
    412           heap.numBlocks = heap.numBlocks / GROWTH_FACTOR;
    413           heap.blocks = (CollectorBlock **)kjs_fast_realloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock *));
    414         }
    415       } 
    416     }
    417   }
    418 
    419   if (deleted) {
     431        // swap with the last block so we compact as we go
     432        heap.blocks[block] = heap.blocks[heap.usedBlocks - 1];
     433        heap.usedBlocks--;
     434        block--; // Don't move forward a step in this case
     435
     436        if (heap.numBlocks > MIN_ARRAY_SIZE && heap.usedBlocks < heap.numBlocks / LOW_WATER_FACTOR) {
     437          heap.numBlocks = heap.numBlocks / GROWTH_FACTOR;
     438          heap.blocks = (CollectorBlock **)kjs_fast_realloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock *));
     439        }
     440      }
     441    }
     442  }
     443
     444  if (heap.numLiveObjects != numLiveObjects)
    420445    heap.firstBlockWithPossibleSpace = 0;
    421   }
    422446 
    423447  int cell = 0;
     
    430454      heap.oversizeCells[cell]->u.freeCell.zeroIfFree = 0;
    431455#else
    432       kjs_fast_free((void *)imp);
     456      kjs_fast_free(imp);
    433457#endif
    434458
     
    437461
    438462      heap.usedOversizeCells--;
    439       deleted = true;
    440463      numLiveObjects--;
    441464
    442465      if (heap.numOversizeCells > MIN_ARRAY_SIZE && heap.usedOversizeCells < heap.numOversizeCells / LOW_WATER_FACTOR) {
    443         heap.numOversizeCells = heap.numOversizeCells / GROWTH_FACTOR;
    444         heap.oversizeCells = (CollectorCell **)kjs_fast_realloc(heap.oversizeCells, heap.numOversizeCells * sizeof(CollectorCell *));
    445       }
    446 
     466        heap.numOversizeCells = heap.numOversizeCells / GROWTH_FACTOR;
     467        heap.oversizeCells = (CollectorCell **)kjs_fast_realloc(heap.oversizeCells, heap.numOversizeCells * sizeof(CollectorCell *));
     468      }
    447469    } else {
    448470      imp->m_marked = false;
     
    451473  }
    452474 
     475  bool deleted = heap.numLiveObjects != numLiveObjects;
     476
    453477  heap.numLiveObjects = numLiveObjects;
    454478  heap.numLiveObjectsAtLastCollect = numLiveObjects;
     
    495519  ProtectedValues::KeyValue *table = ProtectedValues::_table;
    496520  for (int i = 0; i < size; i++) {
    497     ValueImp *val = table[i].key;
     521    AllocatedValueImp *val = table[i].key;
    498522    if (val) {
    499523      ++count;
     
    506530#if APPLE_CHANGES
    507531
    508 static const char *className(ValueImp *val)
     532static const char *className(AllocatedValueImp *val)
    509533{
    510534  const char *name = "???";
     
    543567  ProtectedValues::KeyValue *table = ProtectedValues::_table;
    544568  for (int i = 0; i < size; i++) {
    545     ValueImp *val = table[i].key;
     569    AllocatedValueImp *val = table[i].key;
    546570    if (val) {
    547571      CFStringRef name = CFStringCreateWithCString(NULL, className(val), kCFStringEncodingASCII);
Note: See TracChangeset for help on using the changeset viewer.