From 1ea581170f508b38684f7d89e1b5acd55600e78b Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Wed, 13 May 2015 11:06:52 -0700 Subject: [PATCH] Bug 1163790 - Part 2: Share inlined Class tracing between marking and tenuring; r=bhackett --- js/src/builtin/TypedObject.h | 2 +- js/src/gc/Marking.cpp | 127 ++++++++++++++++++----------------- 2 files changed, 65 insertions(+), 64 deletions(-) diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index 3c6accd6a65..4ec003953e4 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -605,7 +605,7 @@ class TypedObject : public JSObject static bool GetBuffer(JSContext* cx, unsigned argc, Value* vp); static bool GetByteOffset(JSContext* cx, unsigned argc, Value* vp); - Shape* shapeFromGC() { return shape_; } + Shape** addressOfShapeFromGC() { return shape_.unsafeGet(); } }; typedef Handle HandleTypedObject; diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index a0af81e331a..458e0300af0 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1064,6 +1064,64 @@ struct TraverseObjectFunctor } }; +// Call the trace hook set on the object, if present. If further tracing of +// NativeObject fields is required, this will return the native object. +enum class CheckGeneration { DoChecks, NoChecks}; +template +static inline NativeObject* +CallTraceHook(Functor f, JSTracer* trc, JSObject* obj, CheckGeneration check, Args&&... args) +{ + const Class* clasp = obj->getClass(); + MOZ_ASSERT(clasp); + MOZ_ASSERT(obj->isNative() == clasp->isNative()); + + if (!clasp->trace) + return &obj->as(); + + // Global objects all have the same trace hook. That hook is safe without barriers + // if the global has no custom trace hook of its own, or has been moved to a different + // compartment, and so can't have one. + MOZ_ASSERT_IF(!(clasp->trace == JS_GlobalObjectTraceHook && + (!obj->compartment()->options().getTrace() || !obj->isOwnGlobal())), + clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS); + + if (clasp->trace == InlineTypedObject::obj_trace) { + Shape** pshape = obj->as().addressOfShapeFromGC(); + f(pshape, mozilla::Forward(args)...); + + InlineTypedObject& tobj = obj->as(); + if (tobj.typeDescr().hasTraceList()) { + VisitTraceList(f, tobj.typeDescr().traceList(), tobj.inlineTypedMem(), + mozilla::Forward(args)...); + } + + return nullptr; + } + + if (clasp == &UnboxedPlainObject::class_) { + JSObject** pexpando = obj->as().addressOfExpando(); + if (*pexpando) + f(pexpando, mozilla::Forward(args)...); + + UnboxedPlainObject& unboxed = obj->as(); + const UnboxedLayout& layout = check == CheckGeneration::DoChecks + ? unboxed.layout() + : unboxed.layoutDontCheckGeneration(); + if (layout.traceList()) { + VisitTraceList(f, layout.traceList(), unboxed.data(), + mozilla::Forward(args)...); + } + + return nullptr; + } + + clasp->trace(trc, obj); + + if (!clasp->isNative()) + return nullptr; + return &obj->as(); +} + template static void VisitTraceList(F f, const int32_t* traceList, uint8_t* memory, Args&&... args) @@ -1234,44 +1292,11 @@ GCMarker::processMarkStackTop(SliceBudget& budget) ObjectGroup* group = obj->groupFromGC(); traverseEdge(obj, group); - /* Call the trace hook if necessary. */ - const Class* clasp = group->clasp(); - if (clasp->trace) { - // Global objects all have the same trace hook. That hook is safe without barriers - // if the global has no custom trace hook of its own, or has been moved to a different - // compartment, and so can't have one. - MOZ_ASSERT_IF(!(clasp->trace == JS_GlobalObjectTraceHook && - (!obj->compartment()->options().getTrace() || !obj->isOwnGlobal())), - clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS); - if (clasp->trace == InlineTypedObject::obj_trace) { - Shape* shape = obj->as().shapeFromGC(); - traverseEdge(obj, shape); - InlineTypedObject& tobj = obj->as(); - if (tobj.typeDescr().hasTraceList()) { - VisitTraceList(TraverseObjectFunctor(), tobj.typeDescr().traceList(), - tobj.inlineTypedMem(), this, obj); - } - return; - } - if (clasp == &UnboxedPlainObject::class_) { - JSObject* expando = obj->as().maybeExpando(); - if (expando) - traverseEdge(obj, expando); - UnboxedPlainObject& unboxed = obj->as(); - if (unboxed.layout().traceList()) { - VisitTraceList(TraverseObjectFunctor(), unboxed.layout().traceList(), - unboxed.data(), this, obj); - } - return; - } - clasp->trace(this, obj); - } - - if (!clasp->isNative()) + NativeObject *nobj = CallTraceHook(TraverseObjectFunctor(), this, obj, + CheckGeneration::DoChecks, this, obj); + if (!nobj) return; - NativeObject* nobj = &obj->as(); - Shape* shape = nobj->lastProperty(); traverseEdge(obj, shape); @@ -1917,34 +1942,10 @@ struct TenuringFunctor void js::TenuringTracer::traceObject(JSObject* obj) { - const Class* clasp = obj->getClass(); - if (clasp->trace) { - if (clasp->trace == InlineTypedObject::obj_trace) { - InlineTypedObject& tobj = obj->as(); - if (tobj.typeDescr().hasTraceList()) { - VisitTraceList(TenuringFunctor(), tobj.typeDescr().traceList(), - tobj.inlineTypedMem(), *this); - } - return; - } - if (clasp == &UnboxedPlainObject::class_) { - JSObject** pexpando = obj->as().addressOfExpando(); - if (*pexpando) - traverse(pexpando); - UnboxedPlainObject& unboxed = obj->as(); - if (unboxed.layoutDontCheckGeneration().traceList()) { - VisitTraceList(TenuringFunctor(), unboxed.layoutDontCheckGeneration().traceList(), - unboxed.data(), *this); - } - return; - } - clasp->trace(this, obj); - } - - MOZ_ASSERT(obj->isNative() == clasp->isNative()); - if (!clasp->isNative()) + NativeObject *nobj = CallTraceHook(TenuringFunctor(), this, obj, + CheckGeneration::NoChecks, *this); + if (!nobj) return; - NativeObject* nobj = &obj->as(); // Note: the contents of copy on write elements pointers are filled in // during parsing and cannot contain nursery pointers.