Bug 716033 - Move write barriers from jsapi.h to jsfriendapi.h (r=luke,bholley)

This commit is contained in:
Bill McCloskey 2012-01-23 16:43:12 -08:00
parent 6924b97c89
commit 37bab689c0
6 changed files with 101 additions and 187 deletions

View File

@ -6714,79 +6714,6 @@ js_GetCompartmentPrivate(JSCompartment *compartment)
/************************************************************************/
JS_PUBLIC_API(void)
JS_RegisterReference(void **ref)
{
}
JS_PUBLIC_API(void)
JS_ModifyReference(void **ref, void *newval)
{
// XPConnect uses the lower bits of its JSObject refs for evil purposes,
// so we need to fix this.
void *thing = *ref;
*ref = newval;
thing = (void *)((uintptr_t)thing & ~7);
if (!thing)
return;
JS_ASSERT(!static_cast<gc::Cell *>(thing)->compartment()->rt->gcRunning);
uint32_t kind = GetGCThingTraceKind(thing);
if (kind == JSTRACE_OBJECT)
JSObject::writeBarrierPre((JSObject *) thing);
else if (kind == JSTRACE_STRING)
JSString::writeBarrierPre((JSString *) thing);
else
JS_NOT_REACHED("invalid trace kind");
}
JS_PUBLIC_API(void)
JS_UnregisterReference(void **ref)
{
// For now we just want to trigger a write barrier.
JS_ModifyReference(ref, NULL);
}
JS_PUBLIC_API(void)
JS_UnregisterReferenceRT(JSRuntime *rt, void **ref)
{
// For now we just want to trigger a write barrier.
if (!rt->gcRunning)
JS_ModifyReference(ref, NULL);
}
JS_PUBLIC_API(void)
JS_RegisterValue(jsval *val)
{
}
JS_PUBLIC_API(void)
JS_ModifyValue(jsval *val, jsval newval)
{
HeapValue::writeBarrierPre(*val);
*val = newval;
}
JS_PUBLIC_API(void)
JS_UnregisterValue(jsval *val)
{
JS_ModifyValue(val, JSVAL_VOID);
}
JS_PUBLIC_API(void)
JS_UnregisterValueRT(JSRuntime *rt, jsval *val)
{
if (!rt->gcRunning)
JS_ModifyValue(val, JSVAL_VOID);
}
JS_PUBLIC_API(JSTracer *)
JS_GetIncrementalGCTracer(JSRuntime *rt)
{
return rt->gcIncrementalTracer;
}
/************************************************************************/
#if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN)
#include "jswin.h"

View File

@ -3227,105 +3227,6 @@ JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, JSGCTraceKind kind,
#endif
/*
* Write barrier API.
*
* This API is used to inform SpiderMonkey of pointers to JS GC things in the
* malloc heap. There is no need to use this API unless incremental GC is
* enabled. When they are, the requirements for using the API are as follows:
*
* All pointers to JS GC things from the malloc heap must be registered and
* unregistered with the API functions below. This is *in addition* to the
* normal rooting and tracing that must be done normally--these functions will
* not take care of rooting for you.
*
* Besides registration, the JS_ModifyReference function must be called to
* change the value of these references. You should not change them using
* assignment.
*
* Only the RT versions of these functions (which take a JSRuntime argument)
* should be called during GC. Without a JSRuntime, it is not possible to know
* if the object being barriered has already been finalized.
*
* To avoid the headache of using these API functions, the JSBarrieredObjectPtr
* C++ class is provided--simply replace your JSObject* with a
* JSBarrieredObjectPtr. It will take care of calling the registration and
* modification APIs.
*
* For more explanation, see the comment in gc/Barrier.h.
*/
/* These functions are to be used for objects and strings. */
extern JS_PUBLIC_API(void)
JS_RegisterReference(void **ref);
extern JS_PUBLIC_API(void)
JS_ModifyReference(void **ref, void *newval);
extern JS_PUBLIC_API(void)
JS_UnregisterReference(void **ref);
extern JS_PUBLIC_API(void)
JS_UnregisterReferenceRT(JSRuntime *rt, void **ref);
/* These functions are for values. */
extern JS_PUBLIC_API(void)
JS_RegisterValue(jsval *val);
extern JS_PUBLIC_API(void)
JS_ModifyValue(jsval *val, jsval newval);
extern JS_PUBLIC_API(void)
JS_UnregisterValue(jsval *val);
extern JS_PUBLIC_API(void)
JS_UnregisterValueRT(JSRuntime *rt, jsval *val);
extern JS_PUBLIC_API(JSTracer *)
JS_GetIncrementalGCTracer(JSRuntime *rt);
#ifdef __cplusplus
JS_END_EXTERN_C
namespace JS {
class HeapPtrObject
{
JSObject *value;
public:
HeapPtrObject() : value(NULL) { JS_RegisterReference((void **) &value); }
HeapPtrObject(JSObject *obj) : value(obj) { JS_RegisterReference((void **) &value); }
/* Always call finalize before the destructor. */
~HeapPtrObject() { JS_ASSERT(!value); }
void finalize(JSRuntime *rt) {
JS_UnregisterReferenceRT(rt, (void **) &value);
value = NULL;
}
void finalize(JSContext *cx) { finalize(JS_GetRuntime(cx)); }
void init(JSObject *obj) { value = obj; }
JSObject *get() const { return value; }
HeapPtrObject &operator=(JSObject *obj) {
JS_ModifyReference((void **) &value, obj);
return *this;
}
JSObject &operator*() const { return *value; }
JSObject *operator->() const { return value; }
operator JSObject *() const { return value; }
};
} /* namespace JS */
JS_BEGIN_EXTERN_C
#endif
/*
* Garbage collector API.
*/

View File

@ -469,6 +469,39 @@ js::DumpHeapComplete(JSContext *cx, FILE *fp)
namespace js {
JS_FRIEND_API(bool)
IsIncrementalBarrierNeeded(JSRuntime *rt)
{
return !!rt->gcIncrementalTracer && !rt->gcRunning;
}
JS_FRIEND_API(bool)
IsIncrementalBarrierNeeded(JSContext *cx)
{
return IsIncrementalBarrierNeeded(cx->runtime);
}
extern JS_FRIEND_API(void)
IncrementalReferenceBarrier(void *ptr)
{
if (!ptr)
return;
JS_ASSERT(!static_cast<gc::Cell *>(ptr)->compartment()->rt->gcRunning);
uint32_t kind = gc::GetGCThingTraceKind(ptr);
if (kind == JSTRACE_OBJECT)
JSObject::writeBarrierPre((JSObject *) ptr);
else if (kind == JSTRACE_STRING)
JSString::writeBarrierPre((JSString *) ptr);
else
JS_NOT_REACHED("invalid trace kind");
}
extern JS_FRIEND_API(void)
IncrementalValueBarrier(const Value &v)
{
HeapValue::writeBarrierPre(v);
}
/* static */ void
AutoLockGC::LockGC(JSRuntime *rt)
{

View File

@ -565,6 +565,56 @@ GetRuntimeCompartments(JSRuntime *rt);
extern JS_FRIEND_API(size_t)
SizeOfJSContext();
extern JS_FRIEND_API(bool)
IsIncrementalBarrierNeeded(JSRuntime *rt);
extern JS_FRIEND_API(bool)
IsIncrementalBarrierNeeded(JSContext *cx);
extern JS_FRIEND_API(void)
IncrementalReferenceBarrier(void *ptr);
extern JS_FRIEND_API(void)
IncrementalValueBarrier(const Value &v);
class ObjectPtr
{
JSObject *value;
public:
ObjectPtr() : value(NULL) {}
ObjectPtr(JSObject *obj) : value(obj) {}
/* Always call finalize before the destructor. */
~ObjectPtr() { JS_ASSERT(!value); }
void finalize(JSRuntime *rt) {
if (IsIncrementalBarrierNeeded(rt))
IncrementalReferenceBarrier(value);
value = NULL;
}
void finalize(JSContext *cx) { finalize(JS_GetRuntime(cx)); }
void init(JSObject *obj) { value = obj; }
JSObject *get() const { return value; }
void writeBarrierPre(JSRuntime *rt) {
IncrementalReferenceBarrier(value);
}
ObjectPtr &operator=(JSObject *obj) {
IncrementalReferenceBarrier(value);
value = obj;
return *this;
}
JSObject &operator*() const { return *value; }
JSObject *operator->() const { return value; }
operator JSObject *() const { return value; }
};
} /* namespace js */
/*

View File

@ -826,8 +826,6 @@ XPCWrappedNative::XPCWrappedNative(already_AddRefed<nsISupports> aIdentity,
NS_ASSERTION(mSet, "bad ctor param");
DEBUG_TrackNewWrapper(this);
JS_RegisterReference((void **) &mWrapperWord);
}
// This ctor is used if this object will NOT have a proto.
@ -850,8 +848,6 @@ XPCWrappedNative::XPCWrappedNative(already_AddRefed<nsISupports> aIdentity,
NS_ASSERTION(aSet, "bad ctor param");
DEBUG_TrackNewWrapper(this);
JS_RegisterReference((void **) &mWrapperWord);
}
XPCWrappedNative::~XPCWrappedNative()
@ -909,7 +905,8 @@ XPCWrappedNative::Destroy()
* the first time because mWrapperWord isn't used afterwards.
*/
if (XPCJSRuntime *rt = GetRuntime()) {
JS_UnregisterReferenceRT(rt->GetJSRuntime(), (void **) &mWrapperWord);
if (js::IsIncrementalBarrierNeeded(rt->GetJSRuntime()))
js::IncrementalReferenceBarrier(GetWrapperPreserveColor());
mWrapperWord = WRAPPER_WORD_POISON;
} else {
MOZ_ASSERT(mWrapperWord == WRAPPER_WORD_POISON);
@ -925,7 +922,7 @@ XPCWrappedNative::UpdateScriptableInfo(XPCNativeScriptableInfo *si)
// Write barrier for incremental GC.
JSRuntime* rt = GetRuntime()->GetJSRuntime();
if (JS_GetIncrementalGCTracer(rt))
if (js::IsIncrementalBarrierNeeded(rt))
mScriptableInfo->Mark();
mScriptableInfo = si;
@ -936,12 +933,11 @@ XPCWrappedNative::SetProto(XPCWrappedNativeProto* p)
{
NS_ASSERTION(!IsWrapperExpired(), "bad ptr!");
MOZ_ASSERT(HasProto());
// Write barrier for incremental GC.
if (HasProto()) {
JSRuntime* rt = GetRuntime()->GetJSRuntime();
if (JS_GetIncrementalGCTracer(rt))
GetProto()->TraceJS(JS_GetIncrementalGCTracer(rt));
}
JSRuntime* rt = GetRuntime()->GetJSRuntime();
GetProto()->WriteBarrierPre(rt);
mMaybeProto = p;
}

View File

@ -1654,10 +1654,10 @@ private:
// default parent for the XPCWrappedNatives that have us as the scope,
// unless a PreCreate hook overrides it. Note that this _may_ be null (see
// constructor).
JS::HeapPtrObject mGlobalJSObject;
js::ObjectPtr mGlobalJSObject;
// Cached value of Object.prototype
JS::HeapPtrObject mPrototypeJSObject;
js::ObjectPtr mPrototypeJSObject;
// Prototype to use for wrappers with no helper.
JSObject* mPrototypeNoHelper;
@ -2306,6 +2306,12 @@ public:
mScriptableInfo->Mark();
}
void WriteBarrierPre(JSRuntime* rt)
{
if (js::IsIncrementalBarrierNeeded(rt) && mJSProtoObject)
mJSProtoObject.writeBarrierPre(rt);
}
// NOP. This is just here to make the AutoMarkingPtr code compile.
inline void AutoTrace(JSTracer* trc) {}
@ -2348,7 +2354,7 @@ private:
}
XPCWrappedNativeScope* mScope;
JS::HeapPtrObject mJSProtoObject;
js::ObjectPtr mJSProtoObject;
nsCOMPtr<nsIClassInfo> mClassInfo;
PRUint32 mClassInfoFlags;
XPCNativeSet* mSet;
@ -2737,8 +2743,9 @@ public:
}
void SetWrapper(JSObject *obj)
{
js::IncrementalReferenceBarrier(GetWrapperPreserveColor());
PRWord newval = PRWord(obj) | (mWrapperWord & FLAG_MASK);
JS_ModifyReference((void **)&mWrapperWord, (void *)newval);
mWrapperWord = newval;
}
void NoteTearoffs(nsCycleCollectionTraversalCallback& cb);