void Collector::markProtectedObjects() { for (int i = 0; i < ProtectedValues::_tableSize; i++) { ValueImp *val = ProtectedValues::_table[i].key; if (val && !val->marked()) { val->mark(); } } }
void ArrayInstanceImp::mark() { ObjectImp::mark(); unsigned l = storageLength; for (unsigned i = 0; i < l; ++i) { ValueImp *imp = storage[i]; if (imp && !imp->marked()) imp->mark(); } }
void Collector::markStackObjectsConservatively(void *start, void *end) { if (start > end) { void *tmp = start; start = end; end = tmp; } assert(((char *)end - (char *)start) < 0x1000000); assert(IS_POINTER_ALIGNED(start)); assert(IS_POINTER_ALIGNED(end)); char **p = (char **)start; char **e = (char **)end; while (p != e) { char *x = *p++; if (IS_POINTER_ALIGNED(x) && x) { bool good = false; for (int block = 0; block < heap.usedBlocks; block++) { size_t offset = x - (char *)heap.blocks[block]; const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1); if (offset <= lastCellOffset && offset % sizeof(CollectorCell) == 0) { good = true; break; } } if (!good) { int n = heap.usedOversizeCells; for (int i = 0; i != n; i++) { if (x == (char *)heap.oversizeCells[i]) { good = true; break; } } } if (good && ((CollectorCell *)x)->u.freeCell.zeroIfFree != 0) { ValueImp *imp = (ValueImp *)x; if (!imp->marked()) imp->mark(); } } } }
static int compareWithCompareFunctionForQSort(const void *a, const void *b) { CompareWithCompareFunctionArguments *args = compareWithCompareFunctionArguments; ValueImp *va = *(ValueImp **)a; ValueImp *vb = *(ValueImp **)b; if (va->dispatchType() == UndefinedType) { return vb->dispatchType() == UndefinedType ? 0 : 1; } if (vb->dispatchType() == UndefinedType) { return -1; } args->arguments.clear(); args->arguments.append(va); args->arguments.append(vb); double compareResult = args->compareFunction->call (args->exec, args->globalObject, args->arguments).toNumber(args->exec); return compareResult < 0 ? -1 : compareResult > 0 ? 1 : 0; }
Value &Value::operator=(const Value &v) { ValueImp *tmpRep = v.imp(); // Avoid the destruction of the object underneath us by // incrementing the reference on it first if(tmpRep) { tmpRep->ref(); // fprintf(stderr, "Value::operator=(%p)(copying %p) imp=%p ref=%d\n", this, &v, tmpRep, tmpRep->refcount); } if(rep) { rep->deref(); // fprintf(stderr, "Value::operator=(%p)(copying %p) old imp=%p ref=%d\n", this, &v, rep, rep->refcount); } rep = tmpRep; return *this; }
static int compareByStringForQSort(const void *a, const void *b) { ExecState *exec = execForCompareByStringForQSort; ValueImp *va = *(ValueImp **)a; ValueImp *vb = *(ValueImp **)b; if (va->dispatchType() == UndefinedType) { return vb->dispatchType() == UndefinedType ? 0 : 1; } if (vb->dispatchType() == UndefinedType) { return -1; } return compare(va->dispatchToString(exec), vb->dispatchToString(exec)); }
bool Collector::collect() { assert(Interpreter::lockCount() > 0); bool deleted = false; #if TEST_CONSERVATIVE_GC // CONSERVATIVE MARK: mark the root set using conservative GC bit (will compare later) ValueImp::useConservativeMark(true); #endif #if USE_CONSERVATIVE_GC || TEST_CONSERVATIVE_GC if (InterpreterImp::s_hook) { InterpreterImp *scr = InterpreterImp::s_hook; do { //fprintf( stderr, "Collector marking interpreter %p\n",(void*)scr); scr->mark(); scr = scr->next; } while (scr != InterpreterImp::s_hook); } markStackObjectsConservatively(); markProtectedObjects(); #endif #if TEST_CONSERVATIVE_GC ValueImp::useConservativeMark(false); #endif #if !USE_CONSERVATIVE_GC // MARK: first mark all referenced objects recursively // starting out from the set of root objects if (InterpreterImp::s_hook) { InterpreterImp *scr = InterpreterImp::s_hook; do { //fprintf( stderr, "Collector marking interpreter %p\n",(void*)scr); scr->mark(); scr = scr->next; } while (scr != InterpreterImp::s_hook); } // mark any other objects that we wouldn't delete anyway for (int block = 0; block < heap.usedBlocks; block++) { int minimumCellsToProcess = heap.blocks[block]->usedCells; CollectorBlock *curBlock = heap.blocks[block]; for (int cell = 0; cell < CELLS_PER_BLOCK; cell++) { if (minimumCellsToProcess < cell) { goto skip_block_mark; } ValueImp *imp = (ValueImp *)(curBlock->cells + cell); if (((CollectorCell *)imp)->u.freeCell.zeroIfFree != 0) { if ((imp->_flags & (ValueImp::VI_CREATED|ValueImp::VI_MARKED)) == ValueImp::VI_CREATED && ((imp->_flags & ValueImp::VI_GCALLOWED) == 0 || imp->refcount != 0)) { imp->mark(); } } else { minimumCellsToProcess++; } } skip_block_mark: ; } for (int cell = 0; cell < heap.usedOversizeCells; cell++) { ValueImp *imp = (ValueImp *)heap.oversizeCells[cell]; if ((imp->_flags & (ValueImp::VI_CREATED|ValueImp::VI_MARKED)) == ValueImp::VI_CREATED && ((imp->_flags & ValueImp::VI_GCALLOWED) == 0 || imp->refcount != 0)) { imp->mark(); } } #endif // SWEEP: delete everything with a zero refcount (garbage) and unmark everything else int emptyBlocks = 0; for (int block = 0; block < heap.usedBlocks; block++) { CollectorBlock *curBlock = heap.blocks[block]; int minimumCellsToProcess = curBlock->usedCells; for (int cell = 0; cell < CELLS_PER_BLOCK; cell++) { if (minimumCellsToProcess < cell) { goto skip_block_sweep; } ValueImp *imp = (ValueImp *)(curBlock->cells + cell); if (((CollectorCell *)imp)->u.freeCell.zeroIfFree != 0) { #if USE_CONSERVATIVE_GC if (!imp->_marked) #else if (!imp->refcount && imp->_flags == (ValueImp::VI_GCALLOWED | ValueImp::VI_CREATED)) #endif { //fprintf( stderr, "Collector::deleting ValueImp %p (%s)\n", (void*)imp, typeid(*imp).name()); // emulate destructing part of 'operator delete()' imp->~ValueImp(); curBlock->usedCells--; heap.numLiveObjects--; deleted = true; // put it on the free list ((CollectorCell *)imp)->u.freeCell.zeroIfFree = 0; ((CollectorCell *)imp)->u.freeCell.next = curBlock->freeList; curBlock->freeList = (CollectorCell *)imp; } else { #if USE_CONSERVATIVE_GC imp->_marked = 0; #elif TEST_CONSERVATIVE_GC imp->_flags &= ~(ValueImp::VI_MARKED | ValueImp::VI_CONSERVATIVE_MARKED); #else imp->_flags &= ~ValueImp::VI_MARKED; #endif } } else { minimumCellsToProcess++; } } skip_block_sweep: if (heap.blocks[block]->usedCells == 0) { emptyBlocks++; if (emptyBlocks > SPARE_EMPTY_BLOCKS) { #if !DEBUG_COLLECTOR free(heap.blocks[block]); #endif // swap with the last block so we compact as we go heap.blocks[block] = heap.blocks[heap.usedBlocks - 1]; heap.usedBlocks--; block--; // Don't move forward a step in this case if (heap.numBlocks > MIN_ARRAY_SIZE && heap.usedBlocks < heap.numBlocks / LOW_WATER_FACTOR) { heap.numBlocks = heap.numBlocks / GROWTH_FACTOR; heap.blocks = (CollectorBlock **)realloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock *)); } } } } if (deleted) { heap.firstBlockWithPossibleSpace = 0; } int cell = 0; while (cell < heap.usedOversizeCells) { ValueImp *imp = (ValueImp *)heap.oversizeCells[cell]; #if USE_CONSERVATIVE_GC if (!imp->_marked) { #else if (!imp->refcount && imp->_flags == (ValueImp::VI_GCALLOWED | ValueImp::VI_CREATED)) { #endif imp->~ValueImp(); #if DEBUG_COLLECTOR heap.oversizeCells[cell]->u.freeCell.zeroIfFree = 0; #else free((void *)imp); #endif // swap with the last oversize cell so we compact as we go heap.oversizeCells[cell] = heap.oversizeCells[heap.usedOversizeCells - 1]; heap.usedOversizeCells--; deleted = true; heap.numLiveObjects--; if (heap.numOversizeCells > MIN_ARRAY_SIZE && heap.usedOversizeCells < heap.numOversizeCells / LOW_WATER_FACTOR) { heap.numOversizeCells = heap.numOversizeCells / GROWTH_FACTOR; heap.oversizeCells = (CollectorCell **)realloc(heap.oversizeCells, heap.numOversizeCells * sizeof(CollectorCell *)); } } else { #if USE_CONSERVATIVE_GC imp->_marked = 0; #elif TEST_CONSERVATIVE_GC imp->_flags &= ~(ValueImp::VI_MARKED | ValueImp::VI_CONSERVATIVE_MARKED); #else imp->_flags &= ~ValueImp::VI_MARKED; #endif cell++; } } heap.numAllocationsSinceLastCollect = 0; memoryFull = (heap.numLiveObjects >= KJS_MEM_LIMIT); return deleted; } int Collector::size() { return heap.numLiveObjects; } #ifdef KJS_DEBUG_MEM void Collector::finalCheck() { } #endif #if APPLE_CHANGES int Collector::numInterpreters() { int count = 0; if (InterpreterImp::s_hook) { InterpreterImp *scr = InterpreterImp::s_hook; do { ++count; scr = scr->next; } while (scr != InterpreterImp::s_hook); } return count; }
bool testInsertDelete(int numInsert, int numDelete, int delOffset, int randSeed) { srand(randSeed); char str[20]; bool result = true; assert(numDelete >= 0 && numDelete < numInsert); assert(delOffset >= 0 && delOffset+numDelete <= numInsert); PropertyMap map; // add some random numbers int *nums = (int*)malloc(numInsert*sizeof(int)); int i; for (i = 0; i < numInsert; i++) { nums[i] = int(1000.0*rand()/RAND_MAX); Value val = Number(nums[i]); ValueImp *v = val.imp(); v->ref(); sprintf(str,"%05d-%05d",nums[i],i); // ensure uniqueness map.put(str,v,0); map.checkTree(); } // check to ensure they're all there for (i = 0; i < numInsert; i++) { sprintf(str,"%05d-%05d",nums[i],i); ValueImp *v = map.get(str); if (v == 0 || v->type() != NumberType || static_cast<NumberImp*>(v)->value() != nums[i]) { result = false; } map.checkTree(); } // delete some for (i = delOffset; i < delOffset+numDelete; i++) { sprintf(str,"%05d-%05d",nums[i],i); map.remove(str); map.checkTree(); } // make sure the deletes ones aren't there any more, and the others are for (i = 0; i < numInsert; i++) { sprintf(str,"%05d-%05d",nums[i],i); ValueImp *v = map.get(str); if (i >= delOffset && i < delOffset+numDelete) { // should have been deleted if (v) result = false; } else { // should not have been deleted if (v == 0 || v->type() != NumberType || static_cast<NumberImp*>(v)->value() != nums[i]) { result = false; } } map.checkTree(); } // check that first() and next() work PropertyMapNode *it = map.first(); int itcount = 0; while (it) { itcount++; PropertyMapNode *prev = it; it = it->next(); if (it) { if (uscompare(prev->name,it->name) >= 0) result = false; } } if (itcount != numInsert-numDelete) result = false; if (result) printf("PASS: Insert %d, delete %d-%d, seed %d\n",numInsert,delOffset, delOffset+numDelete-1,randSeed); else printf("FAIL: Insert %d, delete %d-%d, seed %d\n",numInsert,delOffset, delOffset+numDelete-1,randSeed); return result; }