Bug 1135985 - Use typed members to implement pushMarkStack; r=sfink

This commit is contained in:
Terrence Cole 2015-02-25 13:09:05 -08:00
parent 98cd9d6d72
commit 773f6b2ed8
11 changed files with 192 additions and 276 deletions

View File

@ -7,11 +7,11 @@
#include "builtin/SymbolObject.h"
#include "vm/StringBuffer.h"
#include "vm/Symbol.h"
#include "jsobjinlines.h"
#include "vm/NativeObject-inl.h"
#include "vm/Symbol-inl.h"
using JS::Symbol;
using namespace js;

View File

@ -26,7 +26,6 @@
#include "gc/Nursery-inl.h"
#include "vm/String-inl.h"
#include "vm/Symbol-inl.h"
using namespace js;
using namespace js::gc;
@ -68,37 +67,43 @@ JS_PUBLIC_DATA(void * const) JS::NullPtr::constNullValue = nullptr;
*/
static inline void
PushMarkStack(GCMarker *gcmarker, JSObject *thing);
PushMarkStack(GCMarker *gcmarker, JSObject *thing) {
gcmarker->traverse(thing);
}
static inline void
PushMarkStack(GCMarker *gcmarker, JSFunction *thing);
PushMarkStack(GCMarker *gcmarker, JSFunction *thing) {
gcmarker->traverse(static_cast<JSObject *>(thing));
}
static inline void
PushMarkStack(GCMarker *gcmarker, JSScript *thing);
PushMarkStack(GCMarker *gcmarker, ObjectGroup *thing) {
gcmarker->traverse(thing);
}
static void
PushMarkStack(GCMarker *gcmarker, jit::JitCode *thing) {
gcmarker->traverse(thing);
}
static inline void
PushMarkStack(GCMarker *gcmarker, JSScript *thing) {
gcmarker->traverse(thing);
}
static inline void
PushMarkStack(GCMarker *gcmarker, LazyScript *thing) {
gcmarker->traverse(thing);
}
static inline void
PushMarkStack(GCMarker *gcmarker, Shape *thing);
static inline void
PushMarkStack(GCMarker *gcmarker, JSString *str);
PushMarkStack(GCMarker *gcmarker, BaseShape *thing);
static inline void
PushMarkStack(GCMarker *gcmarker, JS::Symbol *sym);
PushMarkStack(GCMarker *gcmarker, JSString *thing);
static inline void
PushMarkStack(GCMarker *gcmarker, ObjectGroup *thing);
PushMarkStack(GCMarker *gcmarker, JS::Symbol *thing);
namespace js {
namespace gc {
static void MarkChildren(JSTracer *trc, JSString *str);
static void MarkChildren(JSTracer *trc, JS::Symbol *sym);
static void MarkChildren(JSTracer *trc, JSScript *script);
static void MarkChildren(JSTracer *trc, LazyScript *lazy);
static void MarkChildren(JSTracer *trc, Shape *shape);
static void MarkChildren(JSTracer *trc, BaseShape *base);
static void MarkChildren(JSTracer *trc, ObjectGroup *group);
static void MarkChildren(JSTracer *trc, jit::JitCode *code);
} /* namespace gc */
} /* namespace js */
@ -199,7 +204,7 @@ CheckMarkedThing(JSTracer *trc, T **thingp)
MOZ_ASSERT_IF(gcMarker->shouldCheckCompartments(),
zone->isCollecting() || rt->isAtomsZone(zone));
MOZ_ASSERT_IF(gcMarker->getMarkColor() == GRAY,
MOZ_ASSERT_IF(gcMarker->markColor() == GRAY,
!zone->isGCMarkingBlack() || rt->isAtomsZone(zone));
MOZ_ASSERT(!(zone->isGCSweeping() || zone->isGCFinished() || zone->isGCCompacting()));
@ -938,7 +943,7 @@ ShouldMarkCrossCompartment(JSTracer *trc, JSObject *src, Cell *cell)
if (!IS_GC_MARKING_TRACER(trc))
return true;
uint32_t color = AsGCMarker(trc)->getMarkColor();
uint32_t color = AsGCMarker(trc)->markColor();
MOZ_ASSERT(color == BLACK || color == GRAY);
if (IsInsideNursery(cell)) {
@ -1009,27 +1014,6 @@ gc::MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name)
/*** Push Mark Stack ***/
#define JS_COMPARTMENT_ASSERT(rt, thing) \
MOZ_ASSERT((thing)->zone()->isGCMarking())
#define JS_COMPARTMENT_ASSERT_STR(rt, thing) \
MOZ_ASSERT((thing)->zone()->isGCMarking() || \
(rt)->isAtomsZone((thing)->zone()));
// Symbols can also be in the atoms zone.
#define JS_COMPARTMENT_ASSERT_SYM(rt, sym) \
JS_COMPARTMENT_ASSERT_STR(rt, sym)
static void
PushMarkStack(GCMarker *gcmarker, JSObject *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
if (thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushObject(thing);
}
/*
* PushMarkStack for BaseShape unpacks its children directly onto the mark
* stack. For a pre-barrier between incremental slices, this may result in
@ -1040,61 +1024,10 @@ PushMarkStack(GCMarker *gcmarker, JSObject *thing)
static void
MaybePushMarkStackBetweenSlices(GCMarker *gcmarker, JSObject *thing)
{
DebugOnly<JSRuntime *> rt = gcmarker->runtime();
JS_COMPARTMENT_ASSERT(rt, thing);
MOZ_ASSERT_IF(rt->isHeapBusy(), !IsInsideNursery(thing));
MOZ_ASSERT_IF(gcmarker->runtime()->isHeapBusy(), !IsInsideNursery(thing));
if (!IsInsideNursery(thing) && thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushObject(thing);
}
static void
PushMarkStack(GCMarker *gcmarker, JSFunction *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
if (thing->asTenured().markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushObject(thing);
}
static void
PushMarkStack(GCMarker *gcmarker, ObjectGroup *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushType(thing);
}
static void
PushMarkStack(GCMarker *gcmarker, JSScript *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
/*
* We mark scripts directly rather than pushing on the stack as they can
* refer to other scripts only indirectly (like via nested functions) and
* we cannot get to deep recursion.
*/
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
MarkChildren(gcmarker, thing);
}
static void
PushMarkStack(GCMarker *gcmarker, LazyScript *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
/*
* We mark lazy scripts directly rather than pushing on the stack as they
* only refer to normal scripts and to strings, and cannot recurse.
*/
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
MarkChildren(gcmarker, thing);
if (!IsInsideNursery(thing))
gcmarker->traverse(thing);
}
static void
@ -1107,20 +1040,10 @@ PushMarkStack(GCMarker *gcmarker, Shape *thing)
MOZ_ASSERT(!IsInsideNursery(thing));
/* We mark shapes directly rather than pushing on the stack. */
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
if (thing->markIfUnmarked(gcmarker->markColor()))
ScanShape(gcmarker, thing);
}
static void
PushMarkStack(GCMarker *gcmarker, jit::JitCode *thing)
{
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(thing));
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
gcmarker->pushJitCode(thing);
}
static inline void
ScanBaseShape(GCMarker *gcmarker, BaseShape *base);
@ -1131,7 +1054,7 @@ PushMarkStack(GCMarker *gcmarker, BaseShape *thing)
MOZ_ASSERT(!IsInsideNursery(thing));
/* We mark base shapes directly rather than pushing on the stack. */
if (thing->markIfUnmarked(gcmarker->getMarkColor()))
if (thing->markIfUnmarked(gcmarker->markColor()))
ScanBaseShape(gcmarker, thing);
}
@ -1154,7 +1077,7 @@ ScanShape(GCMarker *gcmarker, Shape *shape)
MaybePushMarkStackBetweenSlices(gcmarker, shape->setterObject());
shape = shape->previous();
if (shape && shape->markIfUnmarked(gcmarker->getMarkColor()))
if (shape && shape->markIfUnmarked(gcmarker->markColor()))
goto restart;
}
@ -1168,7 +1091,7 @@ ScanBaseShape(GCMarker *gcmarker, BaseShape *base)
if (JSObject *parent = base->getObjectParent()) {
MaybePushMarkStackBetweenSlices(gcmarker, parent);
} else if (GlobalObject *global = base->compartment()->unsafeUnbarrieredMaybeGlobal()) {
PushMarkStack(gcmarker, global);
gcmarker->traverse(global);
}
if (JSObject *metadata = base->getObjectMetadata())
@ -1182,14 +1105,14 @@ ScanBaseShape(GCMarker *gcmarker, BaseShape *base)
if (base->isOwned()) {
UnownedBaseShape *unowned = base->baseUnowned();
MOZ_ASSERT(base->compartment() == unowned->compartment());
unowned->markIfUnmarked(gcmarker->getMarkColor());
unowned->markIfUnmarked(gcmarker->markColor());
}
}
static inline void
ScanLinearString(GCMarker *gcmarker, JSLinearString *str)
{
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime(), str);
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), str);
MOZ_ASSERT(str->isMarked());
/*
@ -1202,7 +1125,7 @@ ScanLinearString(GCMarker *gcmarker, JSLinearString *str)
MOZ_ASSERT(str->JSString::isLinear());
if (str->isPermanentAtom())
break;
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime(), str);
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), str);
if (!str->markIfUnmarked())
break;
}
@ -1225,7 +1148,7 @@ ScanRope(GCMarker *gcmarker, JSRope *rope)
for (;;) {
JS_DIAGNOSTICS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING);
JS_DIAGNOSTICS_ASSERT(rope->JSString::isRope());
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime(), rope);
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), rope);
MOZ_ASSERT(rope->isMarked());
JSRope *next = nullptr;
@ -1279,7 +1202,7 @@ PushMarkStack(GCMarker *gcmarker, JSString *str)
if (str->isPermanentAtom())
return;
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime(), str);
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), str);
/*
* As string can only refer to other strings we fully scan its GC graph
@ -1304,58 +1227,13 @@ PushMarkStack(GCMarker *gcmarker, JS::Symbol *sym)
if (sym->isWellKnownSymbol())
return;
JS_COMPARTMENT_ASSERT_SYM(gcmarker->runtime(), sym);
JS_COMPARTMENT_ASSERT(gcmarker->runtime(), sym);
MOZ_ASSERT(!IsInsideNursery(sym));
if (sym->markIfUnmarked())
ScanSymbol(gcmarker, sym);
}
void
gc::MarkChildren(JSTracer *trc, JSObject *obj)
{
obj->markChildren(trc);
}
static void
gc::MarkChildren(JSTracer *trc, JSString *str)
{
if (str->hasBase())
str->markBase(trc);
else if (str->isRope())
str->asRope().markChildren(trc);
}
static void
gc::MarkChildren(JSTracer *trc, JS::Symbol *sym)
{
sym->markChildren(trc);
}
static void
gc::MarkChildren(JSTracer *trc, JSScript *script)
{
script->markChildren(trc);
}
static void
gc::MarkChildren(JSTracer *trc, LazyScript *lazy)
{
lazy->markChildren(trc);
}
static void
gc::MarkChildren(JSTracer *trc, Shape *shape)
{
shape->markChildren(trc);
}
static void
gc::MarkChildren(JSTracer *trc, BaseShape *base)
{
base->markChildren(trc);
}
/*
* This function is used by the cycle collector to trace through the
* children of a BaseShape (and its baseUnowned(), if any). The cycle
@ -1424,10 +1302,10 @@ ScanObjectGroup(GCMarker *gcmarker, ObjectGroup *group)
}
if (group->proto().isObject())
PushMarkStack(gcmarker, group->proto().toObject());
gcmarker->traverse(group->proto().toObject());
if (group->singleton() && !group->lazy())
PushMarkStack(gcmarker, group->singleton());
gcmarker->traverse(group->singleton());
if (group->newScript())
group->newScript()->trace(gcmarker);
@ -1442,10 +1320,10 @@ ScanObjectGroup(GCMarker *gcmarker, ObjectGroup *group)
PushMarkStack(gcmarker, unboxedGroup);
if (TypeDescr *descr = group->maybeTypeDescr())
PushMarkStack(gcmarker, descr);
gcmarker->traverse(descr);
if (JSFunction *fun = group->maybeInterpretedFunction())
PushMarkStack(gcmarker, fun);
gcmarker->traverse(fun);
}
static void
@ -1488,12 +1366,6 @@ gc::MarkChildren(JSTracer *trc, ObjectGroup *group)
}
}
static void
gc::MarkChildren(JSTracer *trc, jit::JitCode *code)
{
code->trace(trc);
}
template<typename T>
static void
PushArenaTyped(GCMarker *gcmarker, ArenaHeader *aheader)
@ -1666,9 +1538,9 @@ GCMarker::processMarkStackOther(uintptr_t tag, uintptr_t addr)
if (restoreValueArray(obj, (void **)&vp, (void **)&end))
pushValueArray(obj, vp, end);
else
pushObject(obj);
repush(obj);
} else if (tag == JitCodeTag) {
MarkChildren(this, reinterpret_cast<jit::JitCode *>(addr));
reinterpret_cast<jit::JitCode *>(addr)->trace(this);
}
}
@ -1676,7 +1548,7 @@ MOZ_ALWAYS_INLINE void
GCMarker::markAndScanString(JSObject *source, JSString *str)
{
if (!str->isPermanentAtom()) {
JS_COMPARTMENT_ASSERT_STR(runtime(), str);
JS_COMPARTMENT_ASSERT(runtime(), str);
MOZ_ASSERT(runtime()->isAtomsZone(str->zone()) || str->zone() == source->zone());
if (str->markIfUnmarked())
ScanString(this, str);
@ -1687,21 +1559,13 @@ MOZ_ALWAYS_INLINE void
GCMarker::markAndScanSymbol(JSObject *source, JS::Symbol *sym)
{
if (!sym->isWellKnownSymbol()) {
JS_COMPARTMENT_ASSERT_SYM(runtime(), sym);
JS_COMPARTMENT_ASSERT(runtime(), sym);
MOZ_ASSERT(runtime()->isAtomsZone(sym->zone()) || sym->zone() == source->zone());
if (sym->markIfUnmarked())
ScanSymbol(this, sym);
}
}
MOZ_ALWAYS_INLINE bool
GCMarker::markObject(JSObject *source, JSObject *obj)
{
JS_COMPARTMENT_ASSERT(runtime(), obj);
MOZ_ASSERT(obj->compartment() == source->compartment());
return obj->asTenured().markIfUnmarked(getMarkColor());
}
inline void
GCMarker::processMarkStackTop(SliceBudget &budget)
{
@ -1756,7 +1620,9 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
markAndScanString(obj, v.toString());
} else if (v.isObject()) {
JSObject *obj2 = &v.toObject();
if (markObject(obj, obj2)) {
MOZ_ASSERT(obj->compartment() == obj2->compartment());
if (mark(obj2)) {
// Save the rest of this value array for later and start scanning obj2's children.N
pushValueArray(obj, vp, end);
obj = obj2;
goto scan_obj;
@ -1777,8 +1643,9 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
unboxedTraceList++;
while (*unboxedTraceList != -1) {
JSObject *obj2 = *reinterpret_cast<JSObject **>(unboxedMemory + *unboxedTraceList);
if (obj2 && markObject(obj, obj2))
pushObject(obj2);
MOZ_ASSERT_IF(obj2, obj->compartment() == obj2->compartment());
if (obj2 && mark(obj2))
repush(obj2);
unboxedTraceList++;
}
unboxedTraceList++;
@ -1788,8 +1655,9 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
markAndScanString(obj, v.toString());
} else if (v.isObject()) {
JSObject *obj2 = &v.toObject();
if (markObject(obj, obj2))
pushObject(obj2);
MOZ_ASSERT(obj->compartment() == obj2->compartment());
if (mark(obj2))
repush(obj2);
} else if (v.isSymbol()) {
markAndScanSymbol(obj, v.toSymbol());
}
@ -1804,12 +1672,12 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
budget.step();
if (budget.isOverBudget()) {
pushObject(obj);
repush(obj);
return;
}
ObjectGroup *group = obj->groupFromGC();
PushMarkStack(this, group);
traverse(group);
Shape *shape = obj->lastProperty();
PushMarkStack(this, shape);
@ -1855,7 +1723,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
if (nobj->denseElementsAreCopyOnWrite()) {
JSObject *owner = nobj->getElementsHeader()->ownerObject();
if (owner != nobj) {
PushMarkStack(this, owner);
traverse(owner);
break;
}
}
@ -1926,40 +1794,47 @@ GCMarker::drainMarkStack(SliceBudget &budget)
return true;
}
template <typename T>
void
GCMarker::markChildren(T *thing)
{
thing->markChildren(this);
}
void
js::TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind)
{
switch (kind) {
case JSTRACE_OBJECT:
MarkChildren(trc, static_cast<JSObject *>(thing));
static_cast<JSObject *>(thing)->markChildren(trc);
break;
case JSTRACE_SCRIPT:
MarkChildren(trc, static_cast<JSScript *>(thing));
static_cast<JSScript *>(thing)->markChildren(trc);
break;
case JSTRACE_STRING:
MarkChildren(trc, static_cast<JSString *>(thing));
static_cast<JSString *>(thing)->markChildren(trc);
break;
case JSTRACE_SYMBOL:
MarkChildren(trc, static_cast<JS::Symbol *>(thing));
static_cast<JS::Symbol *>(thing)->markChildren(trc);
break;
case JSTRACE_BASE_SHAPE:
MarkChildren(trc, static_cast<BaseShape *>(thing));
static_cast<BaseShape *>(thing)->markChildren(trc);
break;
case JSTRACE_JITCODE:
MarkChildren(trc, (js::jit::JitCode *)thing);
static_cast<jit::JitCode *>(thing)->trace(trc);
break;
case JSTRACE_LAZY_SCRIPT:
MarkChildren(trc, static_cast<LazyScript *>(thing));
static_cast<LazyScript *>(thing)->markChildren(trc);
break;
case JSTRACE_SHAPE:
MarkChildren(trc, static_cast<Shape *>(thing));
static_cast<Shape *>(thing)->markChildren(trc);
break;
case JSTRACE_OBJECT_GROUP:
@ -1978,6 +1853,23 @@ AssertNonGrayGCThing(JSTracer *trc, void **thingp, JSGCTraceKind kind)
DebugOnly<Cell *> thing(static_cast<Cell *>(*thingp));
MOZ_ASSERT_IF(thing->isTenured(), !thing->asTenured().isMarked(js::gc::GRAY));
}
template <typename T>
bool
gc::ZoneIsGCMarking(T *thing)
{
return thing->zone()->isGCMarking();
}
template <typename T>
bool
js::gc::ZoneIsAtomsZoneForString(JSRuntime *rt, T *thing)
{
JSGCTraceKind kind = GetGCThingTraceKind(thing);
if (kind == JSTRACE_STRING || kind == JSTRACE_SYMBOL)
return rt->isAtomsZone(thing->zone());
return false;
}
#endif
static void

View File

@ -250,13 +250,6 @@ MarkCrossCompartmentSlot(JSTracer *trc, JSObject *src, HeapValue *dst_slot, cons
/*** Special Cases ***/
/*
* MarkChildren<JSObject> is exposed solely for preWriteBarrier on
* JSObject::swap. It should not be considered external interface.
*/
void
MarkChildren(JSTracer *trc, JSObject *obj);
/*
* Trace through the shape and any shapes it contains to mark
* non-shape children. This is exposed to the JS API as

View File

@ -54,7 +54,7 @@ StoreBuffer::WholeCellEdges::mark(JSTracer *trc) const
JSObject *object = static_cast<JSObject *>(edge);
if (object->is<ArgumentsObject>())
ArgumentsObject::trace(trc, object);
MarkChildren(trc, object);
object->markChildren(trc);
return;
}
MOZ_ASSERT(kind == JSTRACE_JITCODE);

View File

@ -9,13 +9,16 @@
#include "mozilla/DebugOnly.h"
#include "gc/Heap.h"
#include "js/GCAPI.h"
#include "js/SliceBudget.h"
#include "js/TracingAPI.h"
namespace js {
class NativeObject;
class BaseShape;
class GCMarker;
class LazyScript;
class NativeObject;
class ObjectGroup;
namespace gc {
struct ArenaHeader;
@ -124,6 +127,23 @@ class MarkStack
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
};
#ifdef DEBUG
namespace gc {
template <typename T>
extern bool
ZoneIsGCMarking(T *thing);
template <typename T>
extern bool
ZoneIsAtomsZoneForString(JSRuntime *rt, T *thing);
} /* namespace gc */
#endif
#define JS_COMPARTMENT_ASSERT(rt, thing) \
MOZ_ASSERT(gc::ZoneIsGCMarking((thing)) || gc::ZoneIsAtomsZoneForString((rt), (thing)))
class GCMarker : public JSTracer
{
public:
@ -137,21 +157,16 @@ class GCMarker : public JSTracer
void stop();
void reset();
void pushObject(JSObject *obj) {
pushTaggedPtr(ObjectTag, obj);
}
void pushType(ObjectGroup *group) {
pushTaggedPtr(GroupTag, group);
}
void pushJitCode(jit::JitCode *code) {
pushTaggedPtr(JitCodeTag, code);
}
uint32_t getMarkColor() const {
return color;
}
// Mark the given GC thing and traverse its children at some point.
void traverse(JSObject *thing) { markAndPush(ObjectTag, thing); }
void traverse(ObjectGroup *thing) { markAndPush(GroupTag, thing); }
void traverse(jit::JitCode *thing) { markAndPush(JitCodeTag, thing); }
// The following traverse methods traverse immediately, go out-of-line to do so.
void traverse(JSScript *thing) { markAndTraverse(thing); }
void traverse(LazyScript *thing) { markAndTraverse(thing); }
// The other types are marked immediately and inline via a ScanFoo shared
// between PushMarkStack and the processMarkStackTop. Since ScanFoo is
// inline in Marking.cpp, we cannot inline it here, yet.
/*
* Care must be taken changing the mark color from gray to black. The cycle
@ -165,12 +180,12 @@ class GCMarker : public JSTracer
MOZ_ASSERT(color == gc::BLACK);
color = gc::GRAY;
}
void setMarkColorBlack() {
MOZ_ASSERT(isDrained());
MOZ_ASSERT(color == gc::GRAY);
color = gc::BLACK;
}
uint32_t markColor() const { return color; }
inline void delayMarkingArena(gc::ArenaHeader *aheader);
void delayMarkingChildren(const void *thing);
@ -230,7 +245,6 @@ class GCMarker : public JSTracer
ValueArrayTag,
ObjectTag,
GroupTag,
XmlTag,
SavedValueArrayTag,
JitCodeTag,
LastTag = JitCodeTag
@ -240,6 +254,37 @@ class GCMarker : public JSTracer
static_assert(StackTagMask >= uintptr_t(LastTag), "The tag mask must subsume the tags.");
static_assert(StackTagMask <= gc::CellMask, "The tag mask must be embeddable in a Cell*.");
// Push an object onto the stack for later tracing and assert that it has
// already been marked.
void repush(JSObject *obj) {
MOZ_ASSERT(gc::TenuredCell::fromPointer(obj)->isMarked(markColor()));
pushTaggedPtr(ObjectTag, obj);
}
template <typename T>
void markAndPush(StackTag tag, T *thing) {
if (mark(thing))
pushTaggedPtr(tag, thing);
}
template <typename T>
void markAndTraverse(T *thing) {
if (mark(thing))
markChildren(thing);
}
template <typename T>
void markChildren(T *thing);
// Mark the given GC thing, but do not trace its children. Return true
// if the thing became marked.
template <typename T>
bool mark(T *thing) {
JS_COMPARTMENT_ASSERT(runtime(), thing);
MOZ_ASSERT(!IsInsideNursery(gc::TenuredCell::fromPointer(thing)));
return gc::TenuredCell::fromPointer(thing)->markIfUnmarked(markColor());
}
void pushTaggedPtr(StackTag tag, void *ptr) {
checkZone(ptr);
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);

View File

@ -20,6 +20,7 @@
#include "jstypes.h"
#include "gc/Marking.h"
#include "vm/Symbol.h"
#include "vm/Xdr.h"
#include "jscntxtinlines.h"
@ -27,7 +28,6 @@
#include "jsobjinlines.h"
#include "vm/String-inl.h"
#include "vm/Symbol-inl.h"
using namespace js;
using namespace js::gc;

View File

@ -2413,8 +2413,8 @@ JSObject::swap(JSContext *cx, HandleObject a, HandleObject b)
*/
JS::Zone *zone = a->zone();
if (zone->needsIncrementalBarrier()) {
MarkChildren(zone->barrierTracer(), a);
MarkChildren(zone->barrierTracer(), b);
a->markChildren(zone->barrierTracer());
b->markChildren(zone->barrierTracer());
}
NotifyGCPostSwap(a, b, r);

View File

@ -133,13 +133,6 @@ JSRope::new_(js::ExclusiveContext *cx,
return str;
}
inline void
JSRope::markChildren(JSTracer *trc)
{
js::gc::MarkStringUnbarriered(trc, &d.s.u2.left, "left child");
js::gc::MarkStringUnbarriered(trc, &d.s.u3.right, "right child");
}
MOZ_ALWAYS_INLINE void
JSDependentString::init(js::ExclusiveContext *cx, JSLinearString *base, size_t start,
size_t length)
@ -204,13 +197,6 @@ JSDependentString::new_(js::ExclusiveContext *cx, JSLinearString *baseArg, size_
return str;
}
inline void
JSString::markBase(JSTracer *trc)
{
MOZ_ASSERT(hasBase());
js::gc::MarkStringUnbarriered(trc, &d.s.u3.base, "base");
}
MOZ_ALWAYS_INLINE void
JSFlatString::init(const char16_t *chars, size_t length)
{

View File

@ -459,7 +459,10 @@ class JSString : public js::gc::TenuredCell
inline JSLinearString *base() const;
inline void markBase(JSTracer *trc);
void markBase(JSTracer *trc) {
MOZ_ASSERT(hasBase());
js::gc::MarkStringUnbarriered(trc, &d.s.u3.base, "base");
}
/* Only called by the GC for strings with the FINALIZE_STRING kind. */
@ -497,6 +500,8 @@ class JSString : public js::gc::TenuredCell
bool equals(const char *s);
#endif
inline void markChildren(JSTracer *trc);
static MOZ_ALWAYS_INLINE void readBarrier(JSString *thing) {
if (thing->isPermanentAtom())
return;
@ -554,22 +559,25 @@ class JSRope : public JSString
template <typename CharT>
bool copyChars(js::ExclusiveContext *cx, js::ScopedJSFreePtr<CharT> &out) const;
inline JSString *leftChild() const {
JSString *leftChild() const {
MOZ_ASSERT(isRope());
return d.s.u2.left;
}
inline JSString *rightChild() const {
JSString *rightChild() const {
MOZ_ASSERT(isRope());
return d.s.u3.right;
}
inline void markChildren(JSTracer *trc);
void markChildren(JSTracer *trc) {
js::gc::MarkStringUnbarriered(trc, &d.s.u2.left, "left child");
js::gc::MarkStringUnbarriered(trc, &d.s.u3.right, "right child");
}
inline static size_t offsetOfLeft() {
static size_t offsetOfLeft() {
return offsetof(JSRope, d.s.u2.left);
}
inline static size_t offsetOfRight() {
static size_t offsetOfRight() {
return offsetof(JSRope, d.s.u3.right);
}
};
@ -1227,6 +1235,15 @@ JSString::base() const
return d.s.u3.base;
}
inline void
JSString::markChildren(JSTracer *trc)
{
if (hasBase())
markBase(trc);
else if (isRope())
asRope().markChildren(trc);
}
template<>
MOZ_ALWAYS_INLINE const char16_t *
JSLinearString::nonInlineChars(const JS::AutoCheckCannotGC &nogc) const

View File

@ -1,25 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_Symbol_inl_h
#define vm_Symbol_inl_h
#include "vm/Symbol.h"
#include "gc/Marking.h"
#include "js/RootingAPI.h"
#include "jsgcinlines.h"
inline void
JS::Symbol::markChildren(JSTracer *trc)
{
if (description_)
MarkStringUnbarriered(trc, &description_, "description");
}
#endif /* vm_Symbol_inl_h */

View File

@ -15,6 +15,7 @@
#include "jsapi.h"
#include "gc/Barrier.h"
#include "gc/Marking.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
@ -33,7 +34,11 @@ class Symbol : public js::gc::TenuredCell
uint64_t unused2_;
Symbol(SymbolCode code, JSAtom *desc)
: code_(code), description_(desc) {}
: code_(code), description_(desc)
{
// Silence warnings about unused2 being... unused.
(void)unused2_;
}
Symbol(const Symbol &) = delete;
void operator=(const Symbol &) = delete;
@ -51,7 +56,10 @@ class Symbol : public js::gc::TenuredCell
bool isWellKnownSymbol() const { return uint32_t(code_) < WellKnownSymbolLimit; }
static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SYMBOL; }
inline void markChildren(JSTracer *trc);
inline void markChildren(JSTracer *trc) {
if (description_)
js::gc::MarkStringUnbarriered(trc, &description_, "description");
}
inline void finalize(js::FreeOp *) {}
#ifdef DEBUG