Bug 726845 - Make Value marking interfaces indirect; r=billm

This will eventually allow the GC to update Values that reference an Object,
when moving an object.
This commit is contained in:
Terrence Cole 2012-02-15 17:16:53 -08:00
parent 063997e021
commit ba12f349e5
19 changed files with 115 additions and 101 deletions

View File

@ -185,8 +185,11 @@ MapObject::mark(JSTracer *trc, JSObject *obj)
MapObject *mapobj = static_cast<MapObject *>(obj);
if (ValueMap *map = mapobj->getData()) {
for (ValueMap::Range r = map->all(); !r.empty(); r.popFront()) {
gc::MarkValue(trc, r.front().key, "key");
gc::MarkValue(trc, r.front().value, "value");
const HeapValue &key = r.front().key;
HeapValue tmp(key);
gc::MarkValue(trc, &tmp, "key");
JS_ASSERT(tmp.get() == key.get());
gc::MarkValue(trc, &r.front().value, "value");
}
}
}
@ -331,8 +334,12 @@ SetObject::mark(JSTracer *trc, JSObject *obj)
{
SetObject *setobj = static_cast<SetObject *>(obj);
if (ValueSet *set = setobj->getData()) {
for (ValueSet::Range r = set->all(); !r.empty(); r.popFront())
gc::MarkValue(trc, r.front(), "key");
for (ValueSet::Range r = set->all(); !r.empty(); r.popFront()) {
const HeapValue &key = r.front();
HeapValue tmp(key);
gc::MarkValue(trc, &tmp, "key");
JS_ASSERT(tmp.get() == key.get());
}
}
}

View File

@ -134,8 +134,11 @@ inline void
HeapValue::writeBarrierPre(JSCompartment *comp, const Value &value)
{
#ifdef JSGC_INCREMENTAL
if (comp->needsBarrier())
js::gc::MarkValueUnbarriered(comp->barrierTracer(), value, "write barrier");
if (comp->needsBarrier()) {
Value tmp(value);
js::gc::MarkValueUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
JS_ASSERT(tmp == value);
}
#endif
}

View File

@ -319,6 +319,7 @@ class HeapValue
inline void set(JSCompartment *comp, const Value &v);
const Value &get() const { return value; }
Value *unsafeGet() { return &value; }
operator const Value &() const { return value; }
bool isUndefined() const { return value.isUndefined(); }

View File

@ -1270,6 +1270,26 @@ JSContext::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const
return mallocSizeOf(this) + busyArrays.sizeOfExcludingThis(mallocSizeOf);
}
void
JSContext::mark(JSTracer *trc)
{
/* Stack frames and slots are traced by StackSpace::mark. */
/* Mark other roots-by-definition in the JSContext. */
if (globalObject && !hasRunOption(JSOPTION_UNROOTED_GLOBAL))
MarkObjectRoot(trc, globalObject, "global object");
if (isExceptionPending())
MarkValueRoot(trc, &exception, "exception");
if (autoGCRooters)
autoGCRooters->traceAll(trc);
if (sharpObjectMap.depth > 0)
js_TraceSharpMap(trc, &sharpObjectMap);
MarkValueRoot(trc, &iterValue, "iterValue");
}
namespace JS {
#if defined JS_THREADSAFE && defined DEBUG

View File

@ -1121,6 +1121,8 @@ struct JSContext : js::ContextFriendFields
return reinterpret_cast<JSContext *>(uintptr_t(link) - offsetof(JSContext, link));
}
void mark(JSTracer *trc);
private:
/*
* The allocation code calls the function to indicate either OOM failure
@ -1558,18 +1560,18 @@ class AutoShapeVector : public AutoVectorRooter<const Shape *>
class AutoValueArray : public AutoGCRooter
{
const js::Value *start_;
js::Value *start_;
unsigned length_;
public:
AutoValueArray(JSContext *cx, const js::Value *start, unsigned length
AutoValueArray(JSContext *cx, js::Value *start, unsigned length
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, VALARRAY), start_(start), length_(length)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
}
const Value *start() const { return start_; }
Value *start() { return start_; }
unsigned length() const { return length_; }
JS_DECL_USE_GUARD_OBJECT_NOTIFIER

View File

@ -416,8 +416,11 @@ JSCompartment::markCrossCompartmentWrappers(JSTracer *trc)
{
JS_ASSERT(trc->runtime->gcCurrentCompartment);
for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront())
MarkValueRoot(trc, e.front().key, "cross-compartment wrapper");
for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
Value tmp = e.front().key;
MarkValueRoot(trc, &tmp, "cross-compartment wrapper");
JS_ASSERT(tmp == e.front().key);
}
}
void

View File

@ -432,9 +432,8 @@ exn_trace(JSTracer *trc, JSObject *obj)
vcount += elem->argc;
}
vp = GetStackTraceValueBuffer(priv);
for (i = 0; i != vcount; ++i, ++vp) {
MarkValue(trc, *vp, "stack trace argument");
}
for (i = 0; i != vcount; ++i, ++vp)
MarkValue(trc, vp, "stack trace argument");
}
}

View File

@ -530,7 +530,7 @@ args_trace(JSTracer *trc, JSObject *obj)
{
ArgumentsObject &argsobj = obj->asArguments();
ArgumentsData *data = argsobj.data();
MarkValue(trc, data->callee, js_callee_str);
MarkValue(trc, &data->callee, js_callee_str);
MarkValueRange(trc, argsobj.initialLength(), data->slots, js_arguments_str);
/*

View File

@ -1855,7 +1855,7 @@ gc_root_traversal(JSTracer *trc, const RootEntry &entry)
if (entry.value.type == JS_GC_ROOT_GCTHING_PTR)
MarkGCThingRoot(trc, *reinterpret_cast<void **>(entry.key), name);
else
MarkValueRoot(trc, *reinterpret_cast<Value *>(entry.key), name);
MarkValueRoot(trc, reinterpret_cast<Value *>(entry.key), name);
}
static void
@ -1883,7 +1883,7 @@ AutoGCRooter::trace(JSTracer *trc)
{
switch (tag) {
case JSVAL:
MarkValueRoot(trc, static_cast<AutoValueRooter *>(this)->val, "JS::AutoValueRooter.val");
MarkValueRoot(trc, &static_cast<AutoValueRooter *>(this)->val, "JS::AutoValueRooter.val");
return;
case PARSER:
@ -1905,10 +1905,10 @@ AutoGCRooter::trace(JSTracer *trc)
static_cast<AutoPropDescArrayRooter *>(this)->descriptors;
for (size_t i = 0, len = descriptors.length(); i < len; i++) {
PropDesc &desc = descriptors[i];
MarkValueRoot(trc, desc.pd, "PropDesc::pd");
MarkValueRoot(trc, desc.value, "PropDesc::value");
MarkValueRoot(trc, desc.get, "PropDesc::get");
MarkValueRoot(trc, desc.set, "PropDesc::set");
MarkValueRoot(trc, &desc.pd, "PropDesc::pd");
MarkValueRoot(trc, &desc.value, "PropDesc::value");
MarkValueRoot(trc, &desc.get, "PropDesc::get");
MarkValueRoot(trc, &desc.set, "PropDesc::set");
}
return;
}
@ -1917,7 +1917,7 @@ AutoGCRooter::trace(JSTracer *trc)
PropertyDescriptor &desc = *static_cast<AutoPropertyDescriptorRooter *>(this);
if (desc.obj)
MarkObjectRoot(trc, desc.obj, "Descriptor::obj");
MarkValueRoot(trc, desc.value, "Descriptor::value");
MarkValueRoot(trc, &desc.value, "Descriptor::value");
if ((desc.attrs & JSPROP_GETTER) && desc.getter)
MarkObjectRoot(trc, CastAsObject(desc.getter), "Descriptor::get");
if (desc.attrs & JSPROP_SETTER && desc.setter)
@ -1996,26 +1996,6 @@ AutoGCRooter::traceAll(JSTracer *trc)
namespace js {
JS_FRIEND_API(void)
MarkContext(JSTracer *trc, JSContext *acx)
{
/* Stack frames and slots are traced by StackSpace::mark. */
/* Mark other roots-by-definition in acx. */
if (acx->globalObject && !acx->hasRunOption(JSOPTION_UNROOTED_GLOBAL))
MarkObjectRoot(trc, acx->globalObject, "global object");
if (acx->isExceptionPending())
MarkValueRoot(trc, acx->getPendingException(), "exception");
if (acx->autoGCRooters)
acx->autoGCRooters->traceAll(trc);
if (acx->sharpObjectMap.depth > 0)
js_TraceSharpMap(trc, &acx->sharpObjectMap);
MarkValueRoot(trc, acx->iterValue, "iterValue");
}
void
MarkWeakReferences(GCMarker *gcmarker)
{
@ -2053,7 +2033,7 @@ MarkRuntime(JSTracer *trc)
JSContext *iter = NULL;
while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter))
MarkContext(trc, acx);
acx->mark(trc);
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
if (c->activeAnalysis)

View File

@ -45,9 +45,6 @@
* scanning functions, but they don't push onto an explicit stack.
*/
using namespace js;
using namespace js::gc;
namespace js {
namespace gc {
@ -299,43 +296,43 @@ MarkIdRootRange(JSTracer *trc, size_t len, jsid *vec, const char *name)
/*** Value Marking ***/
static inline void
MarkValueInternal(JSTracer *trc, const Value &v)
MarkValueInternal(JSTracer *trc, Value *v)
{
if (v.isMarkable()) {
JS_ASSERT(v.toGCThing());
return MarkKind(trc, v.toGCThing(), v.gcKind());
if (v->isMarkable()) {
JS_ASSERT(v->toGCThing());
return MarkKind(trc, v->toGCThing(), v->gcKind());
}
}
void
MarkValue(JSTracer *trc, const js::HeapValue &v, const char *name)
MarkValue(JSTracer *trc, HeapValue *v, const char *name)
{
JS_SET_TRACING_NAME(trc, name);
MarkValueInternal(trc, v->unsafeGet());
}
void
MarkValueRoot(JSTracer *trc, Value *v, const char *name)
{
JS_SET_TRACING_NAME(trc, name);
MarkValueInternal(trc, v);
}
void
MarkValueRoot(JSTracer *trc, const Value &v, const char *name)
{
JS_SET_TRACING_NAME(trc, name);
MarkValueInternal(trc, v);
}
void
MarkValueRange(JSTracer *trc, size_t len, const HeapValue *vec, const char *name)
MarkValueRange(JSTracer *trc, size_t len, HeapValue *vec, const char *name)
{
for (size_t i = 0; i < len; ++i) {
JS_SET_TRACING_INDEX(trc, name, i);
MarkValueInternal(trc, vec[i]);
MarkValueInternal(trc, vec[i].unsafeGet());
}
}
void
MarkValueRootRange(JSTracer *trc, size_t len, const Value *vec, const char *name)
MarkValueRootRange(JSTracer *trc, size_t len, Value *vec, const char *name)
{
for (size_t i = 0; i < len; ++i) {
JS_SET_TRACING_INDEX(trc, name, i);
MarkValueInternal(trc, vec[i]);
MarkValueInternal(trc, &vec[i]);
}
}
@ -360,17 +357,17 @@ MarkShape(JSTracer *trc, const HeapPtr<const Shape> &thing, const char *name)
}
void
MarkValueUnbarriered(JSTracer *trc, const js::Value &v, const char *name)
MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name)
{
JS_SET_TRACING_NAME(trc, name);
MarkValueInternal(trc, v);
}
void
MarkCrossCompartmentValue(JSTracer *trc, const js::HeapValue &v, const char *name)
MarkCrossCompartmentValue(JSTracer *trc, HeapValue *v, const char *name)
{
if (v.isMarkable()) {
js::gc::Cell *cell = (js::gc::Cell *)v.toGCThing();
if (v->isMarkable()) {
Cell *cell = (Cell *)v->toGCThing();
JSRuntime *rt = trc->runtime;
if (rt->gcCurrentCompartment && cell->compartment() != rt->gcCurrentCompartment)
return;
@ -643,7 +640,7 @@ MarkChildren(JSTracer *trc, JSObject *obj)
uint32_t nslots = obj->slotSpan();
for (uint32_t i = 0; i < nslots; i++) {
JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i);
MarkValueInternal(trc, obj->nativeGetSlot(i));
MarkValueInternal(trc, obj->nativeGetSlotRef(i).unsafeGet());
}
}
}
@ -851,6 +848,8 @@ MarkChildren(JSTracer *trc, JSXML *xml)
} /* namespace gc */
using namespace js::gc;
inline void
GCMarker::processMarkStackTop()
{
@ -916,7 +915,7 @@ GCMarker::processMarkStackTop()
types::TypeObject *type = obj->typeFromGC();
PushMarkStack(this, type);
js::Shape *shape = obj->lastProperty();
Shape *shape = obj->lastProperty();
PushMarkStack(this, shape);
/* Call the trace hook if necessary. */

View File

@ -97,19 +97,19 @@ MarkIdRootRange(JSTracer *trc, size_t len, jsid *vec, const char *name);
/*** Value Marking ***/
void
MarkValue(JSTracer *trc, const js::HeapValue &v, const char *name);
MarkValue(JSTracer *trc, HeapValue *v, const char *name);
void
MarkValueRange(JSTracer *trc, size_t len, const HeapValue *vec, const char *name);
MarkValueRange(JSTracer *trc, size_t len, HeapValue *vec, const char *name);
void
MarkValueRoot(JSTracer *trc, const Value &v, const char *name);
MarkValueRoot(JSTracer *trc, Value *v, const char *name);
void
MarkValueRootRange(JSTracer *trc, size_t len, const Value *vec, const char *name);
MarkValueRootRange(JSTracer *trc, size_t len, Value *vec, const char *name);
inline void
MarkValueRootRange(JSTracer *trc, const Value *begin, const Value *end, const char *name)
MarkValueRootRange(JSTracer *trc, Value *begin, Value *end, const char *name)
{
MarkValueRootRange(trc, end - begin, begin, name);
}
@ -122,14 +122,14 @@ MarkShape(JSTracer *trc, const HeapPtr<const Shape> &thing, const char *name);
/* Direct value access used by the write barriers and the methodjit */
void
MarkValueUnbarriered(JSTracer *trc, const js::Value &v, const char *name);
MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name);
/*
* Mark a value that may be in a different compartment from the compartment
* being GC'd. (Although it won't be marked if it's in the wrong compartment.)
*/
void
MarkCrossCompartmentValue(JSTracer *trc, const js::HeapValue &v, const char *name);
MarkCrossCompartmentValue(JSTracer *trc, HeapValue *v, const char *name);
/*
* MarkChildren<JSObject> is exposed solely for preWriteBarrier on
@ -153,7 +153,7 @@ MarkCycleCollectorChildren(JSTracer *trc, const Shape *shape);
*/
inline void
Mark(JSTracer *trc, const js::HeapValue &v, const char *name)
Mark(JSTracer *trc, HeapValue *v, const char *name)
{
MarkValue(trc, v, name);
}
@ -171,7 +171,7 @@ Mark(JSTracer *trc, const HeapPtr<JSXML> &xml, const char *name)
}
inline bool
IsMarked(const js::Value &v)
IsMarked(const Value &v)
{
if (v.isMarkable())
return !IsAboutToBeFinalized(v);

View File

@ -57,7 +57,7 @@
using namespace js;
using namespace js::gc;
static inline const HeapValue &
static inline HeapValue &
GetCall(JSObject *proxy)
{
JS_ASSERT(IsFunctionProxy(proxy));
@ -72,7 +72,7 @@ GetConstruct(JSObject *proxy)
return proxy->getSlot(JSSLOT_PROXY_CONSTRUCT);
}
static inline const HeapValue &
static inline HeapValue &
GetFunctionProxyConstruct(JSObject *proxy)
{
JS_ASSERT(IsFunctionProxy(proxy));
@ -1246,12 +1246,12 @@ static void
proxy_TraceObject(JSTracer *trc, JSObject *obj)
{
GetProxyHandler(obj)->trace(trc, obj);
MarkCrossCompartmentValue(trc, obj->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "private");
MarkCrossCompartmentValue(trc, obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 0), "extra0");
MarkCrossCompartmentValue(trc, obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 1), "extra1");
MarkCrossCompartmentValue(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "private");
MarkCrossCompartmentValue(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 0), "extra0");
MarkCrossCompartmentValue(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 1), "extra1");
if (IsFunctionProxy(obj)) {
MarkCrossCompartmentValue(trc, GetCall(obj), "call");
MarkCrossCompartmentValue(trc, GetFunctionProxyConstruct(obj), "construct");
MarkCrossCompartmentValue(trc, &GetCall(obj), "call");
MarkCrossCompartmentValue(trc, &GetFunctionProxyConstruct(obj), "construct");
}
}
@ -1259,8 +1259,8 @@ static void
proxy_TraceFunction(JSTracer *trc, JSObject *obj)
{
proxy_TraceObject(trc, obj);
MarkCrossCompartmentValue(trc, GetCall(obj), "call");
MarkCrossCompartmentValue(trc, GetFunctionProxyConstruct(obj), "construct");
MarkCrossCompartmentValue(trc, &GetCall(obj), "call");
MarkCrossCompartmentValue(trc, &GetFunctionProxyConstruct(obj), "construct");
}
static JSBool

View File

@ -1903,6 +1903,6 @@ JSScript::markTrapClosures(JSTracer *trc)
for (unsigned i = 0; i < length; i++) {
BreakpointSite *site = debug->breakpoints[i];
if (site && site->trapHandler)
MarkValue(trc, site->trapClosure, "trap closure");
MarkValue(trc, &site->trapClosure, "trap closure");
}
}

View File

@ -1097,7 +1097,7 @@ class TypedArrayTemplate
static void
obj_trace(JSTracer *trc, JSObject *obj)
{
MarkValue(trc, obj->getFixedSlotRef(FIELD_BUFFER), "typedarray.buffer");
MarkValue(trc, &obj->getFixedSlotRef(FIELD_BUFFER), "typedarray.buffer");
}
static JSBool

View File

@ -91,7 +91,7 @@ namespace js {
// bool isMarked(const Type &x)
// Return true if x has been marked as live by the garbage collector.
//
// bool mark(const Type &x)
// bool mark(Type &x)
// Return false if x is already marked. Otherwise, mark x and return true.
//
// If omitted, the MarkPolicy parameter defaults to js::DefaultMarkPolicy<Type>,
@ -213,7 +213,7 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, publ
bool markedAny = false;
for (Range r = Base::all(); !r.empty(); r.popFront()) {
const Key &k = r.front().key;
const Value &v = r.front().value;
Value &v = r.front().value;
/* If the entry is live, ensure its key and value are marked. */
if (kp.isMarked(k)) {
markedAny |= vp.mark(v);
@ -264,10 +264,10 @@ class DefaultMarkPolicy<HeapValue> {
return !IsAboutToBeFinalized(x);
return true;
}
bool mark(const HeapValue &x) {
bool mark(HeapValue &x) {
if (isMarked(x))
return false;
js::gc::MarkValue(tracer, x, "WeakMap entry");
js::gc::MarkValue(tracer, &x, "WeakMap entry");
return true;
}
};
@ -281,7 +281,7 @@ class DefaultMarkPolicy<HeapPtrObject> {
bool isMarked(const HeapPtrObject &x) {
return !IsAboutToBeFinalized(x);
}
bool mark(const HeapPtrObject &x) {
bool mark(HeapPtrObject &x) {
if (isMarked(x))
return false;
js::gc::MarkObject(tracer, x, "WeakMap entry");
@ -298,7 +298,7 @@ class DefaultMarkPolicy<HeapPtrScript> {
bool isMarked(const HeapPtrScript &x) {
return !IsAboutToBeFinalized(x);
}
bool mark(const HeapPtrScript &x) {
bool mark(HeapPtrScript &x) {
if (isMarked(x))
return false;
js::gc::MarkScript(tracer, x, "WeakMap entry");

View File

@ -367,7 +367,7 @@ Wrapper::iteratorNext(JSContext *cx, JSObject *wrapper, Value *vp)
void
Wrapper::trace(JSTracer *trc, JSObject *wrapper)
{
MarkValue(trc, wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "wrappedObject");
MarkValue(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "wrappedObject");
}
JSObject *
@ -875,7 +875,7 @@ CrossCompartmentWrapper::iteratorNext(JSContext *cx, JSObject *wrapper, Value *v
void
CrossCompartmentWrapper::trace(JSTracer *trc, JSObject *wrapper)
{
MarkCrossCompartmentValue(trc, wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE),
MarkCrossCompartmentValue(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE),
"wrappedObject");
}

View File

@ -1963,7 +1963,7 @@ stubs::ConvertToTypedFloat(JSContext *cx, Value *vp)
void JS_FASTCALL
stubs::WriteBarrier(VMFrame &f, Value *addr)
{
js::gc::MarkValueUnbarriered(f.cx->compartment->barrierTracer(), *addr, "write barrier");
gc::MarkValueUnbarriered(f.cx->compartment->barrierTracer(), addr, "write barrier");
}
void JS_FASTCALL
@ -1971,5 +1971,5 @@ stubs::GCThingWriteBarrier(VMFrame &f, Value *addr)
{
gc::Cell *cell = (gc::Cell *)addr->toGCThing();
if (cell && !cell->isMarked())
gc::MarkValueUnbarriered(f.cx->compartment->barrierTracer(), *addr, "write barrier");
gc::MarkValueUnbarriered(f.cx->compartment->barrierTracer(), addr, "write barrier");
}

View File

@ -275,7 +275,7 @@ StackFrame::mark(JSTracer *trc)
}
if (IS_GC_MARKING_TRACER(trc))
script()->compartment()->active = true;
gc::MarkValueUnbarriered(trc, returnValue(), "rval");
gc::MarkValueUnbarriered(trc, &returnValue(), "rval");
}
/*****************************************************************************/
@ -485,7 +485,7 @@ StackSpace::markFrameSlots(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbyt
/* Will this slot be synced by the JIT? */
if (!analysis->trackSlot(slot) || analysis->liveness(slot).live(offset))
gc::MarkValueRoot(trc, *vp, "vm_stack");
gc::MarkValueRoot(trc, vp, "vm_stack");
else
*vp = UndefinedValue();
}

View File

@ -999,7 +999,7 @@ class StackFrame
return !!(flags_ & HAS_RVAL);
}
const Value &returnValue() {
Value &returnValue() {
if (!(flags_ & HAS_RVAL))
rval_.setUndefined();
return rval_;