/* * The function tries to scan the whole rope tree using the marking stack as * temporary storage. If that becomes full, the unscanned ropes are added to * the delayed marking list. When the function returns, the marking stack is * at the same depth as it was on entry. This way we avoid using tags when * pushing ropes to the stack as ropes never leaks to other users of the * stack. This also assumes that a rope can only point to other ropes or * linear strings, it cannot refer to GC things of other types. */ static void ScanRope(GCMarker *gcmarker, JSRope *rope) { ptrdiff_t savedPos = gcmarker->stack.position(); for (;;) { JS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING); JS_ASSERT(rope->JSString::isRope()); JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, rope); JS_ASSERT(rope->isMarked()); JSRope *next = NULL; JSString *right = rope->rightChild(); if (right->markIfUnmarked()) { if (right->isLinear()) ScanLinearString(gcmarker, &right->asLinear()); else next = &right->asRope(); } JSString *left = rope->leftChild(); if (left->markIfUnmarked()) { if (left->isLinear()) { ScanLinearString(gcmarker, &left->asLinear()); } else { /* * When both children are ropes, set aside the right one to * scan it later. */ if (next && !gcmarker->stack.push(reinterpret_cast<uintptr_t>(next))) gcmarker->delayMarkingChildren(next); next = &left->asRope(); } } if (next) { rope = next; } else if (savedPos != gcmarker->stack.position()) { JS_ASSERT(savedPos < gcmarker->stack.position()); rope = reinterpret_cast<JSRope *>(gcmarker->stack.pop()); } else { break; } } JS_ASSERT(savedPos == gcmarker->stack.position()); }
inline void GCMarker::processMarkStackTop(SliceBudget &budget) { /* * The function uses explicit goto and implements the scanning of the * object directly. It allows to eliminate the tail recursion and * significantly improve the marking performance, see bug 641025. */ HeapSlot *vp, *end; JSObject *obj; uintptr_t addr = stack.pop(); uintptr_t tag = addr & StackTagMask; addr &= ~StackTagMask; if (tag == ValueArrayTag) { JS_STATIC_ASSERT(ValueArrayTag == 0); JS_ASSERT(!(addr & Cell::CellMask)); obj = reinterpret_cast<JSObject *>(addr); uintptr_t addr2 = stack.pop(); uintptr_t addr3 = stack.pop(); JS_ASSERT(addr2 <= addr3); JS_ASSERT((addr3 - addr2) % sizeof(Value) == 0); vp = reinterpret_cast<HeapSlot *>(addr2); end = reinterpret_cast<HeapSlot *>(addr3); goto scan_value_array; } if (tag == ObjectTag) { obj = reinterpret_cast<JSObject *>(addr); JS_COMPARTMENT_ASSERT(runtime, obj); goto scan_obj; } processMarkStackOther(budget, tag, addr); return; scan_value_array: JS_ASSERT(vp <= end); while (vp != end) { const Value &v = *vp++; if (v.isString()) { JSString *str = v.toString(); JS_COMPARTMENT_ASSERT_STR(runtime, str); JS_ASSERT(str->compartment() == runtime->atomsCompartment || str->compartment() == obj->compartment()); if (str->markIfUnmarked()) ScanString(this, str); } else if (v.isObject()) { JSObject *obj2 = &v.toObject(); JS_COMPARTMENT_ASSERT(runtime, obj2); JS_ASSERT(obj->compartment() == obj2->compartment()); if (obj2->markIfUnmarked(getMarkColor())) { pushValueArray(obj, vp, end); obj = obj2; goto scan_obj; } } } return; scan_obj: { JS_COMPARTMENT_ASSERT(runtime, obj); budget.step(); if (budget.isOverBudget()) { pushObject(obj); return; } types::TypeObject *type = obj->typeFromGC(); PushMarkStack(this, type); Shape *shape = obj->lastProperty(); PushMarkStack(this, shape); /* Call the trace hook if necessary. */ Class *clasp = shape->getObjectClass(); if (clasp->trace) { if (clasp == &ArrayClass) { JS_ASSERT(!shape->isNative()); vp = obj->getDenseArrayElements(); end = vp + obj->getDenseArrayInitializedLength(); goto scan_value_array; } else { JS_ASSERT_IF(runtime->gcMode == JSGC_MODE_INCREMENTAL && runtime->gcIncrementalEnabled, clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS); } clasp->trace(this, obj); } if (!shape->isNative()) return; unsigned nslots = obj->slotSpan(); vp = obj->fixedSlots(); if (obj->slots) { unsigned nfixed = obj->numFixedSlots(); if (nslots > nfixed) { pushValueArray(obj, vp, vp + nfixed); vp = obj->slots; end = vp + (nslots - nfixed); goto scan_value_array; } } JS_ASSERT(nslots <= obj->numFixedSlots()); end = vp + nslots; goto scan_value_array; } }