blob: 0180f480ce7dddbc57db413be3462812392bdfc9 [file] [log] [blame]
/* -*- 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 gc_Marking_h
#define gc_Marking_h
#include "jsgc.h"
#include "jscntxt.h"
#include "jslock.h"
#include "gc/Barrier.h"
#include "gc/Nursery.h"
#include "js/TemplateLib.h"
#include "jit/IonCode.h"
extern "C" {
struct JSContext;
class JSFunction;
class JSObject;
class JSScript;
}
class JSAtom;
class JSLinearString;
namespace js {
class ArgumentsObject;
class ArrayBufferObject;
class BaseShape;
class GlobalObject;
class UnownedBaseShape;
class Shape;
template<class, typename> class HeapPtr;
namespace gc {
/*** Object Marking ***/
/*
* These functions expose marking functionality for all of the different GC
* thing kinds. For each GC thing, there are several variants. As an example,
* these are the variants generated for JSObject. They are listed from most to
* least desirable for use:
*
* MarkObject(JSTracer *trc, const HeapPtr<JSObject> &thing, const char *name);
* This function should be used for marking JSObjects, in preference to all
* others below. Use it when you have HeapPtr<JSObject>, which
* automatically implements write barriers.
*
* MarkObjectRoot(JSTracer *trc, JSObject *thing, const char *name);
* This function is only valid during the root marking phase of GC (i.e.,
* when MarkRuntime is on the stack).
*
* MarkObjectUnbarriered(JSTracer *trc, JSObject *thing, const char *name);
* Like MarkObject, this function can be called at any time. It is more
* forgiving, since it doesn't demand a HeapPtr as an argument. Its use
* should always be accompanied by a comment explaining how write barriers
* are implemented for the given field.
*
* Additionally, the functions MarkObjectRange and MarkObjectRootRange are
* defined for marking arrays of object pointers.
*
* The following functions are provided to test whether a GC thing is marked
* under different circumstances:
*
* IsObjectAboutToBeFinalized(JSObject **thing);
* This function is indended to be used in code used to sweep GC things. It
* indicates whether the object will will be finialized in the current group
* of compartments being swept. Note that this will return false for any
* object not in the group of compartments currently being swept, as even if
* it is unmarked it may still become marked before it is swept.
*
* IsObjectMarked(JSObject **thing);
* This function is indended to be used in rare cases in code used to mark
* GC things. It indicates whether the object is currently marked.
*/
#define DeclMarker(base, type) \
void Mark##base(JSTracer *trc, EncapsulatedPtr<type> *thing, const char *name); \
void Mark##base##Root(JSTracer *trc, type **thingp, const char *name); \
void Mark##base##Unbarriered(JSTracer *trc, type **thingp, const char *name); \
void Mark##base##Range(JSTracer *trc, size_t len, HeapPtr<type> *thing, const char *name); \
void Mark##base##RootRange(JSTracer *trc, size_t len, type **thing, const char *name); \
bool Is##base##Marked(type **thingp); \
bool Is##base##Marked(EncapsulatedPtr<type> *thingp); \
bool Is##base##AboutToBeFinalized(type **thingp); \
bool Is##base##AboutToBeFinalized(EncapsulatedPtr<type> *thingp);
DeclMarker(BaseShape, BaseShape)
DeclMarker(BaseShape, UnownedBaseShape)
DeclMarker(IonCode, jit::IonCode)
DeclMarker(Object, ArgumentsObject)
DeclMarker(Object, ArrayBufferObject)
DeclMarker(Object, DebugScopeObject)
DeclMarker(Object, GlobalObject)
DeclMarker(Object, JSObject)
DeclMarker(Object, JSFunction)
DeclMarker(Object, ScopeObject)
DeclMarker(Script, JSScript)
DeclMarker(LazyScript, LazyScript)
DeclMarker(Shape, Shape)
DeclMarker(String, JSAtom)
DeclMarker(String, JSString)
DeclMarker(String, JSFlatString)
DeclMarker(String, JSLinearString)
DeclMarker(String, PropertyName)
DeclMarker(TypeObject, types::TypeObject)
#undef DeclMarker
/* Return true if the pointer is NULL, or if it is a tagged pointer to NULL. */
JS_ALWAYS_INLINE bool
IsNullTaggedPointer(void *p)
{
return uintptr_t(p) < 32;
}
/*** Externally Typed Marking ***/
/*
* Note: this must only be called by the GC and only when we are tracing through
* MarkRoots. It is explicitly for ConservativeStackMarking and should go away
* after we transition to exact rooting.
*/
void
MarkKind(JSTracer *trc, void **thingp, JSGCTraceKind kind);
void
MarkGCThingRoot(JSTracer *trc, void **thingp, const char *name);
void
MarkGCThingUnbarriered(JSTracer *trc, void **thingp, const char *name);
/*** ID Marking ***/
void
MarkId(JSTracer *trc, EncapsulatedId *id, const char *name);
void
MarkIdRoot(JSTracer *trc, jsid *id, const char *name);
void
MarkIdUnbarriered(JSTracer *trc, jsid *id, const char *name);
void
MarkIdRange(JSTracer *trc, size_t len, HeapId *vec, const char *name);
void
MarkIdRootRange(JSTracer *trc, size_t len, jsid *vec, const char *name);
/*** Value Marking ***/
void
MarkValue(JSTracer *trc, EncapsulatedValue *v, const char *name);
void
MarkValueRange(JSTracer *trc, size_t len, EncapsulatedValue *vec, const char *name);
inline void
MarkValueRange(JSTracer *trc, HeapValue *begin, HeapValue *end, const char *name)
{
return MarkValueRange(trc, end - begin, begin, name);
}
void
MarkValueRoot(JSTracer *trc, Value *v, const char *name);
void
MarkThingOrValueUnbarriered(JSTracer *trc, uintptr_t *word, const char *name);
void
MarkValueRootRange(JSTracer *trc, size_t len, Value *vec, const char *name);
inline void
MarkValueRootRange(JSTracer *trc, Value *begin, Value *end, const char *name)
{
MarkValueRootRange(trc, end - begin, begin, name);
}
void
MarkTypeRoot(JSTracer *trc, types::Type *v, const char *name);
bool
IsValueMarked(Value *v);
bool
IsValueAboutToBeFinalized(Value *v);
/*** Slot Marking ***/
void
MarkSlot(JSTracer *trc, HeapSlot *s, const char *name);
void
MarkArraySlots(JSTracer *trc, size_t len, HeapSlot *vec, const char *name);
void
MarkObjectSlots(JSTracer *trc, JSObject *obj, uint32_t start, uint32_t nslots);
void
MarkCrossCompartmentObjectUnbarriered(JSTracer *trc, JSObject *src, JSObject **dst_obj,
const char *name);
void
MarkCrossCompartmentScriptUnbarriered(JSTracer *trc, JSObject *src, JSScript **dst_script,
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
MarkCrossCompartmentSlot(JSTracer *trc, JSObject *src, HeapSlot *dst_slot, const char *name);
/*** Special Cases ***/
/*
* The unioned HeapPtr stored in script->globalObj needs special treatment to
* typecheck correctly.
*/
void
MarkObject(JSTracer *trc, HeapPtr<GlobalObject, JSScript *> *thingp, const char *name);
/* Direct value access used by the write barriers and the methodjit. */
void
MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name);
/*
* MarkChildren<JSObject> is exposed solely for preWriteBarrier on
* JSObject::TradeGuts. 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
* JS_TraceShapeCycleCollectorChildren.
*/
void
MarkCycleCollectorChildren(JSTracer *trc, Shape *shape);
void
PushArena(GCMarker *gcmarker, ArenaHeader *aheader);
/*** Generic ***/
/*
* The Mark() functions interface should only be used by code that must be
* templated. Other uses should use the more specific, type-named functions.
*/
inline void
Mark(JSTracer *trc, EncapsulatedValue *v, const char *name)
{
MarkValue(trc, v, name);
}
inline void
Mark(JSTracer *trc, EncapsulatedPtrObject *o, const char *name)
{
MarkObject(trc, o, name);
}
inline void
Mark(JSTracer *trc, EncapsulatedPtrScript *o, const char *name)
{
MarkScript(trc, o, name);
}
inline void
Mark(JSTracer *trc, HeapPtr<jit::IonCode> *code, const char *name)
{
MarkIonCode(trc, code, name);
}
/* For use by WeakMap's HashKeyRef instantiation. */
inline void
Mark(JSTracer *trc, JSObject **objp, const char *name)
{
MarkObjectUnbarriered(trc, objp, name);
}
/* For use by Debugger::WeakMap's proxiedScopes HashKeyRef instantiation. */
inline void
Mark(JSTracer *trc, ScopeObject **obj, const char *name)
{
MarkObjectUnbarriered(trc, obj, name);
}
bool
IsCellMarked(Cell **thingp);
bool
IsCellAboutToBeFinalized(Cell **thing);
inline bool
IsMarked(EncapsulatedValue *v)
{
if (!v->isMarkable())
return true;
return IsValueMarked(v->unsafeGet());
}
inline bool
IsMarked(EncapsulatedPtrObject *objp)
{
return IsObjectMarked(objp);
}
inline bool
IsMarked(EncapsulatedPtrScript *scriptp)
{
return IsScriptMarked(scriptp);
}
inline bool
IsAboutToBeFinalized(EncapsulatedValue *v)
{
if (!v->isMarkable())
return false;
return IsValueAboutToBeFinalized(v->unsafeGet());
}
inline bool
IsAboutToBeFinalized(EncapsulatedPtrObject *objp)
{
return IsObjectAboutToBeFinalized(objp);
}
inline bool
IsAboutToBeFinalized(EncapsulatedPtrScript *scriptp)
{
return IsScriptAboutToBeFinalized(scriptp);
}
#ifdef JS_ION
/* Nonsense to get WeakCache to work with new Marking semantics. */
inline bool
IsAboutToBeFinalized(const js::jit::VMFunction **vmfunc)
{
/*
* Preserves entries in the WeakCache<VMFunction, IonCode>
* iff the IonCode has been marked.
*/
return true;
}
inline bool
IsAboutToBeFinalized(ReadBarriered<js::jit::IonCode> code)
{
return IsIonCodeAboutToBeFinalized(code.unsafeGet());
}
#endif
inline Cell *
ToMarkable(const Value &v)
{
if (v.isMarkable())
return (Cell *)v.toGCThing();
return NULL;
}
inline Cell *
ToMarkable(Cell *cell)
{
return cell;
}
inline JSGCTraceKind
TraceKind(const Value &v)
{
JS_ASSERT(v.isMarkable());
if (v.isObject())
return JSTRACE_OBJECT;
return JSTRACE_STRING;
}
inline JSGCTraceKind
TraceKind(JSObject *obj)
{
return JSTRACE_OBJECT;
}
inline JSGCTraceKind
TraceKind(JSScript *script)
{
return JSTRACE_SCRIPT;
}
inline JSGCTraceKind
TraceKind(LazyScript *lazy)
{
return JSTRACE_LAZY_SCRIPT;
}
} /* namespace gc */
void
TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind);
} /* namespace js */
#endif /* gc_Marking_h */