This commit is contained in:
Terrence Cole 2014-07-28 10:16:56 -07:00
Родитель 9bc76bfb73
Коммит 68b8d91b1f
16 изменённых файлов: 148 добавлений и 78 удалений

Просмотреть файл

@ -151,12 +151,40 @@
*/
class JSAtom;
struct JSCompartment;
class JSFlatString;
class JSLinearString;
namespace JS {
class Symbol;
}
namespace js {
class ArgumentsObject;
class ArrayBufferObject;
class ArrayBufferViewObject;
class SharedArrayBufferObject;
class BaseShape;
class DebugScopeObject;
class GlobalObject;
class LazyScript;
class Nursery;
class ObjectImpl;
class PropertyName;
class SavedFrame;
class ScopeObject;
class ScriptSourceObject;
class Shape;
class UnownedBaseShape;
namespace types {
struct TypeObject;
}
namespace jit {
class JitCode;
}
#ifdef DEBUG
bool
@ -173,6 +201,32 @@ StringIsPermanentAtom(JSString *str);
namespace gc {
template <typename T> struct MapTypeToTraceKind {};
template <> struct MapTypeToTraceKind<ArgumentsObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ArrayBufferViewObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<BaseShape> { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; };
template <> struct MapTypeToTraceKind<DebugScopeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<GlobalObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<JS::Symbol> { static const JSGCTraceKind kind = JSTRACE_SYMBOL; };
template <> struct MapTypeToTraceKind<JSAtom> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<JSFlatString> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<JSFunction> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<JSLinearString> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<JSObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<JSScript> { static const JSGCTraceKind kind = JSTRACE_SCRIPT; };
template <> struct MapTypeToTraceKind<JSString> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<LazyScript> { static const JSGCTraceKind kind = JSTRACE_LAZY_SCRIPT; };
template <> struct MapTypeToTraceKind<ObjectImpl> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<PropertyName> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<SavedFrame> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ScopeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<Shape> { static const JSGCTraceKind kind = JSTRACE_SHAPE; };
template <> struct MapTypeToTraceKind<SharedArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<UnownedBaseShape> { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; };
template <> struct MapTypeToTraceKind<jit::JitCode> { static const JSGCTraceKind kind = JSTRACE_JITCODE; };
template <> struct MapTypeToTraceKind<types::TypeObject>{ static const JSGCTraceKind kind = JSTRACE_TYPE_OBJECT; };
template <typename T>
void
MarkUnbarriered(JSTracer *trc, T **thingp, const char *name);
@ -206,6 +260,7 @@ class BarrieredCell : public gc::Cell
static MOZ_ALWAYS_INLINE void readBarrier(T *thing) {
#ifdef JSGC_INCREMENTAL
JS_ASSERT(!CurrentThreadIsIonCompiling());
JS_ASSERT(!T::isNullLike(thing));
JS::shadow::Zone *shadowZone = thing->shadowZoneFromAnyThread();
if (shadowZone->needsIncrementalBarrier()) {
MOZ_ASSERT(!RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone));
@ -213,6 +268,8 @@ class BarrieredCell : public gc::Cell
js::gc::MarkUnbarriered<T>(shadowZone->barrierTracer(), &tmp, "read barrier");
JS_ASSERT(tmp == thing);
}
if (JS::GCThingIsMarkedGray(thing))
JS::UnmarkGrayGCThingRecursively(thing, MapTypeToTraceKind<T>::kind);
#endif
}
@ -771,6 +828,10 @@ class ReadBarriered
return value;
}
T unbarrieredGet() const {
return value;
}
operator T() const { return get(); }
T &operator*() const { return *get(); }

Просмотреть файл

@ -1142,7 +1142,7 @@ ScanBaseShape(GCMarker *gcmarker, BaseShape *base)
if (JSObject *parent = base->getObjectParent()) {
MaybePushMarkStackBetweenSlices(gcmarker, parent);
} else if (GlobalObject *global = base->compartment()->maybeGlobal()) {
} else if (GlobalObject *global = base->compartment()->unsafeUnbarrieredMaybeGlobal()) {
PushMarkStack(gcmarker, global);
}
@ -1961,10 +1961,13 @@ UnmarkGrayChildren(JSTracer *trc, void **thingp, JSGCTraceKind kind)
JS_FRIEND_API(bool)
JS::UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind)
{
JS_ASSERT(kind != JSTRACE_SHAPE);
JSRuntime *rt = static_cast<Cell *>(thing)->runtimeFromMainThread();
// When the ReadBarriered type is used in a HashTable, it is difficult or
// impossible to suppress the implicit cast operator while iterating for GC.
if (rt->isHeapBusy())
return false;
bool unmarkedArg = false;
if (!IsInsideNursery(static_cast<Cell *>(thing))) {
if (!JS::GCThingIsMarkedGray(thing))

Просмотреть файл

@ -183,6 +183,9 @@ struct JSCompartment
*/
inline js::GlobalObject *maybeGlobal() const;
/* An unbarriered getter for use while tracing. */
inline js::GlobalObject *unsafeUnbarrieredMaybeGlobal() const;
inline void initGlobal(js::GlobalObject &global);
public:

Просмотреть файл

@ -28,6 +28,12 @@ JSCompartment::maybeGlobal() const
return global_;
}
js::GlobalObject *
JSCompartment::unsafeUnbarrieredMaybeGlobal() const
{
return *global_.unsafeGet();
}
js::AutoCompartment::AutoCompartment(ExclusiveContext *cx, JSObject *target)
: cx_(cx),
origin_(cx->compartment_)

Просмотреть файл

@ -4520,7 +4520,7 @@ GCRuntime::endSweepPhase(JSGCInvocationKind gckind, bool lastGC)
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
if (e.front().key().kind != CrossCompartmentKey::StringWrapper)
AssertNotOnGrayList(&e.front().value().get().toObject());
AssertNotOnGrayList(&e.front().value().unbarrieredGet().toObject());
}
}
#endif

Просмотреть файл

@ -20,32 +20,8 @@
#include "js/SliceBudget.h"
#include "js/Vector.h"
class JSAtom;
struct JSCompartment;
class JSFlatString;
class JSLinearString;
namespace JS {
class Symbol;
} /* namespace JS */
namespace js {
class ArgumentsObject;
class ArrayBufferObject;
class ArrayBufferViewObject;
class SharedArrayBufferObject;
class BaseShape;
class DebugScopeObject;
class GlobalObject;
class LazyScript;
class Nursery;
class PropertyName;
class SavedFrame;
class ScopeObject;
class Shape;
class UnownedBaseShape;
namespace gc {
class ForkJoinNursery;
}
@ -104,32 +80,6 @@ MapAllocToTraceKind(AllocKind kind)
return map[kind];
}
template <typename T> struct MapTypeToTraceKind {};
template <> struct MapTypeToTraceKind<ObjectImpl> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<JSObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<JSFunction> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ArgumentsObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ArrayBufferViewObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<SharedArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<DebugScopeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<GlobalObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ScopeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<SavedFrame> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<JSScript> { static const JSGCTraceKind kind = JSTRACE_SCRIPT; };
template <> struct MapTypeToTraceKind<LazyScript> { static const JSGCTraceKind kind = JSTRACE_LAZY_SCRIPT; };
template <> struct MapTypeToTraceKind<Shape> { static const JSGCTraceKind kind = JSTRACE_SHAPE; };
template <> struct MapTypeToTraceKind<BaseShape> { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; };
template <> struct MapTypeToTraceKind<UnownedBaseShape> { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; };
template <> struct MapTypeToTraceKind<types::TypeObject>{ static const JSGCTraceKind kind = JSTRACE_TYPE_OBJECT; };
template <> struct MapTypeToTraceKind<JSAtom> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<JSString> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<JSFlatString> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<JSLinearString> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<JS::Symbol> { static const JSGCTraceKind kind = JSTRACE_SYMBOL; };
template <> struct MapTypeToTraceKind<PropertyName> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<jit::JitCode> { static const JSGCTraceKind kind = JSTRACE_JITCODE; };
/* Return a printable string for the given kind, for diagnostic purposes. */
const char *
TraceKindAsAscii(JSGCTraceKind kind);

Просмотреть файл

@ -2322,7 +2322,7 @@ TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
}
for (gc::ZoneCellIter i(cx->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
RootedScript script(cx, i.get<JSScript>());
JSScript *script = i.get<JSScript>();
if (script->types) {
unsigned count = TypeScript::NumTypeSets(script);
StackTypeSet *typeArray = script->types->typeArray();
@ -4122,7 +4122,7 @@ TypeCompartment::sweep(FreeOp *fop)
bool remove = false;
TypeObject *typeObject = nullptr;
if (!key.type.isUnknown() && key.type.isTypeObject()) {
typeObject = key.type.typeObject();
typeObject = key.type.typeObjectNoBarrier();
if (IsTypeObjectAboutToBeFinalized(&typeObject))
remove = true;
}
@ -4131,7 +4131,7 @@ TypeCompartment::sweep(FreeOp *fop)
if (remove) {
e.removeFront();
} else if (typeObject && typeObject != key.type.typeObject()) {
} else if (typeObject && typeObject != key.type.typeObjectNoBarrier()) {
ArrayTableKey newKey;
newKey.type = Type::ObjectType(typeObject);
newKey.proto = key.proto;
@ -4160,10 +4160,10 @@ TypeCompartment::sweep(FreeOp *fop)
JS_ASSERT(!entry.types[i].isSingleObject());
TypeObject *typeObject = nullptr;
if (entry.types[i].isTypeObject()) {
typeObject = entry.types[i].typeObject();
typeObject = entry.types[i].typeObjectNoBarrier();
if (IsTypeObjectAboutToBeFinalized(&typeObject))
remove = true;
else if (typeObject != entry.types[i].typeObject())
else if (typeObject != entry.types[i].typeObjectNoBarrier())
entry.types[i] = Type::ObjectType(typeObject);
}
}
@ -4203,7 +4203,7 @@ JSCompartment::sweepNewTypeObjectTable(TypeObjectWithNewScriptSet &table)
e.removeFront();
} else if (entry.newFunction && IsObjectAboutToBeFinalized(&entry.newFunction)) {
e.removeFront();
} else if (entry.object != e.front().object) {
} else if (entry.object.unbarrieredGet() != e.front().object.unbarrieredGet()) {
TypeObjectWithNewScriptSet::Lookup lookup(entry.object->clasp(),
entry.object->proto(),
entry.newFunction);

Просмотреть файл

@ -664,7 +664,13 @@ JSObject::global() const
while (JSObject *parent = obj->getParent())
obj = parent;
#endif
return *compartment()->maybeGlobal();
/*
* The global is read-barriered so that it is kept live by access through
* the JSCompartment. When accessed through a JSObject, however, the global
* will be already be kept live by the black JSObject's parent pointer, so
* does not need to be read-barriered.
*/
return *compartment()->unsafeUnbarrieredMaybeGlobal();
}
inline bool

Просмотреть файл

@ -145,10 +145,10 @@ PropertyTree::getChild(ExclusiveContext *cx, Shape *parentArg, StackShape &unroo
if (kidp->isShape()) {
Shape *kid = kidp->toShape();
if (kid->matches(unrootedChild))
existingShape = kid;
existingShape = kid;
} else if (kidp->isHash()) {
if (KidsHash::Ptr p = kidp->toHash()->lookup(unrootedChild))
existingShape = *p;
existingShape = *p;
} else {
/* If kidp->isNull(), we always insert. */
}
@ -174,6 +174,8 @@ PropertyTree::getChild(ExclusiveContext *cx, Shape *parentArg, StackShape &unroo
JS_ASSERT(parent->isMarked());
parent->removeChild(existingShape);
existingShape = nullptr;
} else if (existingShape->isMarked(gc::GRAY)) {
JS::UnmarkGrayGCThingRecursively(existingShape, JSTRACE_SHAPE);
}
}
#endif

Просмотреть файл

@ -271,10 +271,6 @@ WeakMap_get_impl(JSContext *cx, CallArgs args)
if (ObjectValueMap *map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
// Read barrier to prevent an incorrectly gray value from escaping the
// weak map. See the comment before UnmarkGrayChildren in gc/Marking.cpp
ExposeValueToActiveJS(ptr->value().get());
args.rval().set(ptr->value());
return true;
}
@ -450,6 +446,7 @@ JS_NondeterministicGetWeakMapKeys(JSContext *cx, HandleObject objArg, MutableHan
// Prevent GC from mutating the weakmap while iterating.
AutoSuppressGC suppress(cx);
for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) {
JS::ExposeObjectToActiveJS(r.front().key());
RootedObject key(cx, r.front().key());
if (!cx->compartment()->wrap(cx, &key))
return false;

Просмотреть файл

@ -111,6 +111,8 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, publ
typedef typename Base::Enum Enum;
typedef typename Base::Lookup Lookup;
typedef typename Base::Range Range;
typedef typename Base::Ptr Ptr;
typedef typename Base::AddPtr AddPtr;
explicit WeakMap(JSContext *cx, JSObject *memOf = nullptr)
: Base(cx->runtime()), WeakMapBase(memOf, cx->compartment()) { }
@ -124,7 +126,34 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, publ
return true;
}
// Overwritten to add a read barrier to prevent an incorrectly gray value
// from escaping the weak map. See the comment before UnmarkGrayChildren in
// gc/Marking.cpp
Ptr lookup(const Lookup &l) const {
Ptr p = Base::lookup(l);
if (p)
exposeGCThingToActiveJS(p->value());
return p;
}
AddPtr lookupForAdd(const Lookup &l) const {
AddPtr p = Base::lookupForAdd(l);
if (p)
exposeGCThingToActiveJS(p->value());
return p;
}
Ptr lookupWithDefault(const Key &k, const Value &defaultValue) {
Ptr p = Base::lookupWithDefault(k, defaultValue);
if (p)
exposeGCThingToActiveJS(p->value());
return p;
}
private:
void exposeGCThingToActiveJS(const JS::Value &v) const { JS::ExposeValueToActiveJS(v); }
void exposeGCThingToActiveJS(JSObject *obj) const { JS::ExposeObjectToActiveJS(obj); }
bool markValue(JSTracer *trc, Value *x) {
if (gc::IsMarked(x))
return false;

Просмотреть файл

@ -18,6 +18,7 @@
#include "frontend/BytecodeCompiler.h"
#include "gc/Marking.h"
#include "jit/BaselineJIT.h"
#include "js/GCAPI.h"
#include "js/Vector.h"
#include "vm/ArgumentsObject.h"
#include "vm/DebuggerMemory.h"
@ -1426,10 +1427,13 @@ Debugger::slowPathOnNewGlobalObject(JSContext *cx, Handle<GlobalObject *> global
AutoObjectVector watchers(cx);
for (JSCList *link = JS_LIST_HEAD(&cx->runtime()->onNewGlobalObjectWatchers);
link != &cx->runtime()->onNewGlobalObjectWatchers;
link = JS_NEXT_LINK(link)) {
link = JS_NEXT_LINK(link))
{
Debugger *dbg = fromOnNewGlobalObjectWatchersLink(link);
JS_ASSERT(dbg->observesNewGlobalObject());
if (!watchers.append(dbg->object))
JSObject *obj = dbg->object;
JS::ExposeObjectToActiveJS(obj);
if (!watchers.append(obj))
return;
}
@ -2674,6 +2678,10 @@ class Debugger::ScriptQuery {
return false;
}
/* We cannot touch the gray bits while isHeapBusy, so do this now. */
for (JSScript **i = vector->begin(); i != vector->end(); ++i)
JS::ExposeScriptToActiveJS(*i);
/*
* For most queries, we just accumulate results in 'vector' as we find
* them. But if this is an 'innermost' query, then we've accumulated the
@ -2683,7 +2691,9 @@ class Debugger::ScriptQuery {
if (innermost) {
for (CompartmentToScriptMap::Range r = innermostForCompartment.all();
!r.empty();
r.popFront()) {
r.popFront())
{
JS::ExposeScriptToActiveJS(r.front().value());
if (!v->append(r.front().value())) {
js_ReportOutOfMemory(cx);
return false;

Просмотреть файл

@ -452,8 +452,8 @@ SavedStacks::sweep(JSRuntime *rt)
sweepPCLocationMap();
if (savedFrameProto && IsObjectAboutToBeFinalized(&savedFrameProto)) {
savedFrameProto = nullptr;
if (savedFrameProto && IsObjectAboutToBeFinalized(savedFrameProto.unsafeGet())) {
savedFrameProto.set(nullptr);
}
}
@ -593,9 +593,11 @@ SavedStacks::getOrCreateSavedFramePrototype(JSContext *cx)
|| !JS_DefineProperties(cx, proto, SavedFrame::properties)
|| !JS_DefineFunctions(cx, proto, SavedFrame::methods)
|| !JSObject::freeze(cx, proto))
{
return nullptr;
}
savedFrameProto = proto;
savedFrameProto.set(proto);
// The only object with the SavedFrame::class_ that doesn't have a source
// should be the prototype.
savedFrameProto->setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue());

Просмотреть файл

@ -115,7 +115,7 @@ class SavedStacks {
private:
SavedFrame::Set frames;
JSObject *savedFrameProto;
ReadBarrieredObject savedFrameProto;
bool insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFrame frame,
unsigned maxFrameCount = 0);

Просмотреть файл

@ -1528,7 +1528,7 @@ JSCompartment::sweepBaseShapeTable()
if (baseShapes.initialized()) {
for (BaseShapeSet::Enum e(baseShapes); !e.empty(); e.popFront()) {
UnownedBaseShape *base = e.front();
UnownedBaseShape *base = e.front().unbarrieredGet();
if (IsBaseShapeAboutToBeFinalized(&base))
e.removeFront();
}
@ -1816,7 +1816,7 @@ JSCompartment::sweepInitialShapeTable()
if (initialShapes.initialized()) {
for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) {
const InitialShapeEntry &entry = e.front();
Shape *shape = entry.shape;
Shape *shape = entry.shape.unbarrieredGet();
JSObject *proto = entry.proto.raw();
if (IsShapeAboutToBeFinalized(&shape) || (entry.proto.isObject() && IsObjectAboutToBeFinalized(&proto))) {
e.removeFront();
@ -1826,7 +1826,7 @@ JSCompartment::sweepInitialShapeTable()
JS_ASSERT(!parent || !IsObjectAboutToBeFinalized(&parent));
JS_ASSERT(parent == shape->getObjectParent());
#endif
if (shape != entry.shape || proto != entry.proto.raw()) {
if (shape != entry.shape.unbarrieredGet() || proto != entry.proto.raw()) {
ReadBarrieredShape readBarrieredShape(shape);
InitialShapeEntry newKey(readBarrieredShape, TaggedProto(proto));
e.rekeyFront(newKey.getLookup(), newKey);

Просмотреть файл

@ -369,7 +369,8 @@ InterpreterFrame::mark(JSTracer *trc)
}
if (IS_GC_MARKING_TRACER(trc))
script()->compartment()->zone()->active = true;
gc::MarkValueUnbarriered(trc, returnValue().address(), "rval");
if (hasReturnValue())
gc::MarkValueUnbarriered(trc, &rval_, "rval");
}
void