LCOV - code coverage report
Current view: directory - js/src - jsgcmark.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 556 448 80.6 %
Date: 2012-07-07 Functions: 226 138 61.1 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  */
       3                 : /* This Source Code Form is subject to the terms of the Mozilla Public
       4                 :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       5                 :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6                 : 
       7                 : #include "jsgcmark.h"
       8                 : #include "jsprf.h"
       9                 : #include "jsscope.h"
      10                 : #include "jsstr.h"
      11                 : 
      12                 : #include "jsobjinlines.h"
      13                 : #include "jsscopeinlines.h"
      14                 : 
      15                 : #include "vm/String-inl.h"
      16                 : #include "methodjit/MethodJIT.h"
      17                 : 
      18                 : /*
      19                 :  * There are two mostly separate mark paths. The first is a fast path used
      20                 :  * internally in the GC. The second is a slow path used for root marking and
      21                 :  * for API consumers like the cycle collector or Class::trace implementations.
      22                 :  *
      23                 :  * The fast path uses explicit stacks. The basic marking process during a GC is
      24                 :  * that all roots are pushed on to a mark stack, and then each item on the
      25                 :  * stack is scanned (possibly pushing more stuff) until the stack is empty.
      26                 :  *
      27                 :  * PushMarkStack pushes a GC thing onto the mark stack. In some cases (shapes
      28                 :  * or strings) it eagerly marks the object rather than pushing it. Popping and
      29                 :  * scanning is done by the processMarkStackTop method. For efficiency reasons
      30                 :  * like tail recursion elimination that method also implements the scanning of
      31                 :  * objects. For other GC things it uses helper methods.
      32                 :  *
      33                 :  * Most of the marking code outside jsgcmark uses functions like MarkObject,
      34                 :  * MarkString, etc. These functions check if an object is in the compartment
      35                 :  * currently being GCed. If it is, they call PushMarkStack. Roots are pushed
      36                 :  * this way as well as pointers traversed inside trace hooks (for things like
      37                 :  * IteratorClass). It it always valid to call a MarkX function instead of
      38                 :  * PushMarkStack, although it may be slower.
      39                 :  *
      40                 :  * The MarkX functions also handle non-GC object traversal. In this case, they
      41                 :  * call a callback for each object visited. This is a recursive process; the
      42                 :  * mark stacks are not involved. These callbacks may ask for the outgoing
      43                 :  * pointers to be visited. Eventually, this leads to the MarkChildren functions
      44                 :  * being called. These functions duplicate much of the functionality of
      45                 :  * scanning functions, but they don't push onto an explicit stack.
      46                 :  */
      47                 : 
      48                 : namespace js {
      49                 : namespace gc {
      50                 : 
      51                 : static inline void
      52                 : PushMarkStack(GCMarker *gcmarker, JSXML *thing);
      53                 : 
      54                 : static inline void
      55                 : PushMarkStack(GCMarker *gcmarker, JSObject *thing);
      56                 : 
      57                 : static inline void
      58                 : PushMarkStack(GCMarker *gcmarker, JSFunction *thing);
      59                 : 
      60                 : static inline void
      61                 : PushMarkStack(GCMarker *gcmarker, JSScript *thing);
      62                 : 
      63                 : static inline void
      64                 : PushMarkStack(GCMarker *gcmarker, Shape *thing);
      65                 : 
      66                 : static inline void
      67                 : PushMarkStack(GCMarker *gcmarker, JSString *thing);
      68                 : 
      69                 : static inline void
      70                 : PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing);
      71                 : 
      72                 : /*** Object Marking ***/
      73                 : 
      74                 : template<typename T>
      75                 : static inline void
      76       459276651 : CheckMarkedThing(JSTracer *trc, T *thing)
      77                 : {
      78       459276651 :     JS_ASSERT(trc);
      79       459276651 :     JS_ASSERT(thing);
      80       459276651 :     JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
      81       459276651 :     JS_ASSERT_IF(trc->runtime->gcCurrentCompartment, IS_GC_MARKING_TRACER(trc));
      82                 : 
      83       459276651 :     JS_ASSERT(thing->isAligned());
      84                 : 
      85       459276651 :     JS_ASSERT(thing->compartment());
      86       459276651 :     JS_ASSERT(thing->compartment()->rt == trc->runtime);
      87       459276651 : }
      88                 : 
      89                 : template<typename T>
      90                 : void
      91       459276651 : MarkInternal(JSTracer *trc, T *thing)
      92                 : {
      93       459276651 :     CheckMarkedThing(trc, thing);
      94                 : 
      95       459276651 :     JSRuntime *rt = trc->runtime;
      96                 : 
      97       459276651 :     JS_ASSERT_IF(rt->gcCheckCompartment,
      98                 :                  thing->compartment() == rt->gcCheckCompartment ||
      99                 :                  thing->compartment() == rt->atomsCompartment);
     100                 : 
     101                 :     /*
     102                 :      * Don't mark things outside a compartment if we are in a per-compartment
     103                 :      * GC.
     104                 :      */
     105       459276651 :     if (!rt->gcCurrentCompartment || thing->compartment() == rt->gcCurrentCompartment) {
     106       458188780 :         if (!trc->callback) {
     107       413291014 :             PushMarkStack(static_cast<GCMarker *>(trc), thing);
     108                 :         } else {
     109        44897766 :             void *tmp = (void *)thing;
     110        44897766 :             trc->callback(trc, &tmp, GetGCThingTraceKind(thing));
     111        44897766 :             JS_ASSERT(tmp == thing);
     112                 :         }
     113                 :     }
     114                 : 
     115                 : #ifdef DEBUG
     116       459276651 :     trc->debugPrinter = NULL;
     117       459276651 :     trc->debugPrintArg = NULL;
     118                 : #endif
     119       459276651 : }
     120                 : 
     121                 : #define JS_ROOT_MARKING_ASSERT(trc)                                     \
     122                 :     JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc),                             \
     123                 :                  trc->runtime->gcIncrementalState == NO_INCREMENTAL ||  \
     124                 :                  trc->runtime->gcIncrementalState == MARK_ROOTS);
     125                 : 
     126                 : 
     127                 : template <typename T>
     128                 : static void
     129       370830039 : MarkUnbarriered(JSTracer *trc, T **thingp, const char *name)
     130                 : {
     131       370830039 :     JS_SET_TRACING_NAME(trc, name);
     132       370830039 :     MarkInternal(trc, *thingp);
     133       370830039 : }
     134                 : 
     135                 : template <typename T>
     136                 : static void
     137        28574954 : Mark(JSTracer *trc, HeapPtr<T> *thing, const char *name)
     138                 : {
     139        28574954 :     JS_SET_TRACING_NAME(trc, name);
     140        28574954 :     MarkInternal(trc, thing->get());
     141        28574954 : }
     142                 : 
     143                 : template <typename T>
     144                 : static void
     145        20755634 : MarkRoot(JSTracer *trc, T **thingp, const char *name)
     146                 : {
     147        20755634 :     JS_ROOT_MARKING_ASSERT(trc);
     148        20755634 :     JS_SET_TRACING_NAME(trc, name);
     149        20755634 :     MarkInternal(trc, *thingp);
     150        20755634 : }
     151                 : 
     152                 : template <typename T>
     153                 : static void
     154         2256401 : MarkRange(JSTracer *trc, size_t len, HeapPtr<T> *vec, const char *name)
     155                 : {
     156         6898611 :     for (size_t i = 0; i < len; ++i) {
     157         4642210 :         if (T *obj = vec[i]) {
     158         4642210 :             JS_SET_TRACING_INDEX(trc, name, i);
     159         4642210 :             MarkInternal(trc, obj);
     160                 :         }
     161                 :     }
     162         2256401 : }
     163                 : 
     164                 : template <typename T>
     165                 : static void
     166             716 : MarkRootRange(JSTracer *trc, size_t len, T **vec, const char *name)
     167                 : {
     168             716 :     JS_ROOT_MARKING_ASSERT(trc);
     169            4004 :     for (size_t i = 0; i < len; ++i) {
     170            3288 :         JS_SET_TRACING_INDEX(trc, name, i);
     171            3288 :         MarkInternal(trc, vec[i]);
     172                 :     }
     173             716 : }
     174                 : 
     175                 : #define DeclMarkerImpl(base, type)                                                                \
     176                 : void                                                                                              \
     177                 : Mark##base(JSTracer *trc, HeapPtr<type> *thing, const char *name)                                 \
     178                 : {                                                                                                 \
     179                 :     Mark<type>(trc, thing, name);                                                                 \
     180                 : }                                                                                                 \
     181                 :                                                                                                   \
     182                 : void                                                                                              \
     183                 : Mark##base##Root(JSTracer *trc, type **thingp, const char *name)                                  \
     184                 : {                                                                                                 \
     185                 :     MarkRoot<type>(trc, thingp, name);                                                            \
     186                 : }                                                                                                 \
     187                 :                                                                                                   \
     188                 : void                                                                                              \
     189                 : Mark##base##Unbarriered(JSTracer *trc, type **thingp, const char *name)                           \
     190                 : {                                                                                                 \
     191                 :     MarkUnbarriered<type>(trc, thingp, name);                                                     \
     192                 : }                                                                                                 \
     193                 :                                                                                                   \
     194                 : void Mark##base##Range(JSTracer *trc, size_t len, HeapPtr<type> *vec, const char *name)           \
     195                 : {                                                                                                 \
     196                 :     MarkRange<type>(trc, len, vec, name);                                                         \
     197                 : }                                                                                                 \
     198                 :                                                                                                   \
     199                 : void Mark##base##RootRange(JSTracer *trc, size_t len, type **vec, const char *name)               \
     200                 : {                                                                                                 \
     201                 :     MarkRootRange<type>(trc, len, vec, name);                                                     \
     202                 : }                                                                                                 \
     203                 : 
     204         3712586 : DeclMarkerImpl(BaseShape, BaseShape)
     205           38056 : DeclMarkerImpl(BaseShape, UnownedBaseShape)
     206            1396 : DeclMarkerImpl(Object, ArgumentsObject)
     207           66905 : DeclMarkerImpl(Object, GlobalObject)
     208        12172938 : DeclMarkerImpl(Object, JSObject)
     209         7399257 : DeclMarkerImpl(Object, JSFunction)
     210        13658858 : DeclMarkerImpl(Script, JSScript)
     211        13171054 : DeclMarkerImpl(Shape, Shape)
     212       368696742 : DeclMarkerImpl(String, JSAtom)
     213          160178 : DeclMarkerImpl(String, JSString)
     214            7657 : DeclMarkerImpl(String, JSFlatString)
     215            9567 : DeclMarkerImpl(String, JSLinearString)
     216         3319989 : DeclMarkerImpl(TypeObject, types::TypeObject)
     217                 : #if JS_HAS_XML_SUPPORT
     218            2561 : DeclMarkerImpl(XML, JSXML)
     219                 : #endif
     220                 : 
     221                 : /*** Externally Typed Marking ***/
     222                 : 
     223                 : void
     224        30659757 : MarkKind(JSTracer *trc, void *thing, JSGCTraceKind kind)
     225                 : {
     226        30659757 :     JS_ASSERT(thing);
     227        30659757 :     JS_ASSERT(kind == GetGCThingTraceKind(thing));
     228        30659757 :     switch (kind) {
     229                 :       case JSTRACE_OBJECT:
     230        24025237 :         MarkInternal(trc, reinterpret_cast<JSObject *>(thing));
     231        24025237 :         break;
     232                 :       case JSTRACE_STRING:
     233         3530878 :         MarkInternal(trc, reinterpret_cast<JSString *>(thing));
     234         3530878 :         break;
     235                 :       case JSTRACE_SCRIPT:
     236         1757028 :         MarkInternal(trc, static_cast<JSScript *>(thing));
     237         1757028 :         break;
     238                 :       case JSTRACE_SHAPE:
     239         1174022 :         MarkInternal(trc, reinterpret_cast<Shape *>(thing));
     240         1174022 :         break;
     241                 :       case JSTRACE_BASE_SHAPE:
     242          137997 :         MarkInternal(trc, reinterpret_cast<BaseShape *>(thing));
     243          137997 :         break;
     244                 :       case JSTRACE_TYPE_OBJECT:
     245           34550 :         MarkInternal(trc, reinterpret_cast<types::TypeObject *>(thing));
     246           34550 :         break;
     247                 : #if JS_HAS_XML_SUPPORT
     248                 :       case JSTRACE_XML:
     249              45 :         MarkInternal(trc, static_cast<JSXML *>(thing));
     250              45 :         break;
     251                 : #endif
     252                 :     }
     253        30659757 : }
     254                 : 
     255                 : void
     256          134800 : MarkGCThingRoot(JSTracer *trc, void *thing, const char *name)
     257                 : {
     258          134800 :     JS_ROOT_MARKING_ASSERT(trc);
     259          134800 :     JS_SET_TRACING_NAME(trc, name);
     260          134800 :     if (!thing)
     261               0 :         return;
     262          134800 :     MarkKind(trc, thing, GetGCThingTraceKind(thing));
     263                 : }
     264                 : 
     265                 : /*** ID Marking ***/
     266                 : 
     267                 : static inline void
     268         4599942 : MarkIdInternal(JSTracer *trc, jsid *id)
     269                 : {
     270         4599942 :     if (JSID_IS_STRING(*id)) {
     271         3710025 :         JSString *str = JSID_TO_STRING(*id);
     272         3710025 :         MarkInternal(trc, str);
     273         3710025 :         *id = ATOM_TO_JSID(reinterpret_cast<JSAtom *>(str));
     274          889917 :     } else if (JS_UNLIKELY(JSID_IS_OBJECT(*id))) {
     275               0 :         JSObject *obj = JSID_TO_OBJECT(*id);
     276               0 :         MarkInternal(trc, obj);
     277               0 :         *id = OBJECT_TO_JSID(obj);
     278                 :     }
     279         4599942 : }
     280                 : 
     281                 : void
     282         4548215 : MarkId(JSTracer *trc, HeapId *id, const char *name)
     283                 : {
     284         4548215 :     JS_SET_TRACING_NAME(trc, name);
     285         4548215 :     MarkIdInternal(trc, id->unsafeGet());
     286         4548215 : }
     287                 : 
     288                 : void
     289               0 : MarkIdRoot(JSTracer *trc, jsid *id, const char *name)
     290                 : {
     291               0 :     JS_ROOT_MARKING_ASSERT(trc);
     292               0 :     JS_SET_TRACING_NAME(trc, name);
     293               0 :     MarkIdInternal(trc, id);
     294               0 : }
     295                 : 
     296                 : void
     297               0 : MarkIdRange(JSTracer *trc, size_t len, HeapId *vec, const char *name)
     298                 : {
     299               0 :     for (size_t i = 0; i < len; ++i) {
     300               0 :         JS_SET_TRACING_INDEX(trc, name, i);
     301               0 :         MarkIdInternal(trc, vec[i].unsafeGet());
     302                 :     }
     303               0 : }
     304                 : 
     305                 : void
     306            1643 : MarkIdRootRange(JSTracer *trc, size_t len, jsid *vec, const char *name)
     307                 : {
     308            1643 :     JS_ROOT_MARKING_ASSERT(trc);
     309           53370 :     for (size_t i = 0; i < len; ++i) {
     310           51727 :         JS_SET_TRACING_INDEX(trc, name, i);
     311           51727 :         MarkIdInternal(trc, &vec[i]);
     312                 :     }
     313            1643 : }
     314                 : 
     315                 : /*** Value Marking ***/
     316                 : 
     317                 : static inline void
     318        30123493 : MarkValueInternal(JSTracer *trc, Value *v)
     319                 : {
     320        30123493 :     if (v->isMarkable()) {
     321        10164224 :         JS_ASSERT(v->toGCThing());
     322        10164224 :         return MarkKind(trc, v->toGCThing(), v->gcKind());
     323                 :     }
     324                 : }
     325                 : 
     326                 : void
     327           15293 : MarkValue(JSTracer *trc, HeapValue *v, const char *name)
     328                 : {
     329           15293 :     JS_SET_TRACING_NAME(trc, name);
     330           15293 :     MarkValueInternal(trc, v->unsafeGet());
     331           15293 : }
     332                 : 
     333                 : void
     334           61598 : MarkValueRoot(JSTracer *trc, Value *v, const char *name)
     335                 : {
     336           61598 :     JS_ROOT_MARKING_ASSERT(trc);
     337           61598 :     JS_SET_TRACING_NAME(trc, name);
     338           61598 :     MarkValueInternal(trc, v);
     339           61598 : }
     340                 : 
     341                 : void
     342         8391266 : MarkValueRange(JSTracer *trc, size_t len, HeapValue *vec, const char *name)
     343                 : {
     344        24873202 :     for (size_t i = 0; i < len; ++i) {
     345        16481936 :         JS_SET_TRACING_INDEX(trc, name, i);
     346        16481936 :         MarkValueInternal(trc, vec[i].unsafeGet());
     347                 :     }
     348         8391266 : }
     349                 : 
     350                 : void
     351          657545 : MarkValueRootRange(JSTracer *trc, size_t len, Value *vec, const char *name)
     352                 : {
     353          657545 :     JS_ROOT_MARKING_ASSERT(trc);
     354         3877907 :     for (size_t i = 0; i < len; ++i) {
     355         3220362 :         JS_SET_TRACING_INDEX(trc, name, i);
     356         3220362 :         MarkValueInternal(trc, &vec[i]);
     357                 :     }
     358          657545 : }
     359                 : 
     360                 : /*** Slot Marking ***/
     361                 : 
     362                 : void
     363           83038 : MarkSlot(JSTracer *trc, HeapSlot *s, const char *name)
     364                 : {
     365           83038 :     JS_SET_TRACING_NAME(trc, name);
     366           83038 :     MarkValueInternal(trc, s->unsafeGet());
     367           83038 : }
     368                 : 
     369                 : void
     370           20964 : MarkArraySlots(JSTracer *trc, size_t len, HeapSlot *vec, const char *name)
     371                 : {
     372           63831 :     for (size_t i = 0; i < len; ++i) {
     373           42867 :         JS_SET_TRACING_INDEX(trc, name, i);
     374           42867 :         MarkValueInternal(trc, vec[i].unsafeGet());
     375                 :     }
     376           20964 : }
     377                 : 
     378                 : void
     379         3250879 : MarkObjectSlots(JSTracer *trc, JSObject *obj, uint32_t start, uint32_t nslots)
     380                 : {
     381         3250879 :     JS_ASSERT(obj->isNative());
     382        12846679 :     for (uint32_t i = start; i < (start + nslots); ++i) {
     383         9595800 :         JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i);
     384         9595800 :         MarkValueInternal(trc, obj->nativeGetSlotRef(i).unsafeGet());
     385                 :     }
     386         3250879 : }
     387                 : 
     388                 : void
     389          169662 : MarkCrossCompartmentSlot(JSTracer *trc, HeapSlot *s, const char *name)
     390                 : {
     391          169662 :     if (s->isMarkable()) {
     392           83407 :         Cell *cell = (Cell *)s->toGCThing();
     393           83407 :         JSRuntime *rt = trc->runtime;
     394           83407 :         if (rt->gcCurrentCompartment && cell->compartment() != rt->gcCurrentCompartment)
     395             420 :             return;
     396                 : 
     397                 :         /* In case we're called from a write barrier. */
     398           82987 :         if (rt->gcIncrementalCompartment && cell->compartment() != rt->gcIncrementalCompartment)
     399               0 :             return;
     400                 : 
     401           82987 :         MarkSlot(trc, s, name);
     402                 :     }
     403                 : }
     404                 : 
     405                 : /*** Special Marking ***/
     406                 : 
     407                 : void
     408          100744 : MarkObject(JSTracer *trc, HeapPtr<GlobalObject, JSScript *> *thingp, const char *name)
     409                 : {
     410          100744 :     JS_SET_TRACING_NAME(trc, name);
     411          100744 :     MarkInternal(trc, thingp->get());
     412          100744 : }
     413                 : 
     414                 : void
     415          622599 : MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name)
     416                 : {
     417          622599 :     JS_SET_TRACING_NAME(trc, name);
     418          622599 :     MarkValueInternal(trc, v);
     419          622599 : }
     420                 : 
     421                 : /*** Push Mark Stack ***/
     422                 : 
     423                 : #define JS_COMPARTMENT_ASSERT(rt, thing)                                 \
     424                 :     JS_ASSERT_IF((rt)->gcCurrentCompartment,                             \
     425                 :                  (thing)->compartment() == (rt)->gcCurrentCompartment);
     426                 : 
     427                 : #define JS_COMPARTMENT_ASSERT_STR(rt, thing)                             \
     428                 :     JS_ASSERT_IF((rt)->gcCurrentCompartment,                             \
     429                 :                  (thing)->compartment() == (rt)->gcCurrentCompartment || \
     430                 :                  (thing)->compartment() == (rt)->atomsCompartment);
     431                 : 
     432                 : static void
     433            2563 : PushMarkStack(GCMarker *gcmarker, JSXML *thing)
     434                 : {
     435            2563 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     436                 : 
     437            2563 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     438            2520 :         gcmarker->pushXML(thing);
     439            2563 : }
     440                 : 
     441                 : static void
     442        52066614 : PushMarkStack(GCMarker *gcmarker, JSObject *thing)
     443                 : {
     444        52066614 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     445                 : 
     446        52066614 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     447        12277381 :         gcmarker->pushObject(thing);
     448        52066614 : }
     449                 : 
     450                 : static void
     451         7656635 : PushMarkStack(GCMarker *gcmarker, JSFunction *thing)
     452                 : {
     453         7656635 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     454                 : 
     455         7656635 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     456         4931234 :         gcmarker->pushObject(thing);
     457         7656635 : }
     458                 : 
     459                 : static void
     460        54291368 : PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing)
     461                 : {
     462        54291368 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     463                 : 
     464        54291368 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     465         2101784 :         gcmarker->pushType(thing);
     466        54291368 : }
     467                 : 
     468                 : static void
     469                 : MarkChildren(JSTracer *trc, JSScript *script);
     470                 : 
     471                 : static void
     472        15221160 : PushMarkStack(GCMarker *gcmarker, JSScript *thing)
     473                 : {
     474        15221160 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     475                 : 
     476                 :     /*
     477                 :      * We mark scripts directly rather than pushing on the stack as they can
     478                 :      * refer to other scripts only indirectly (like via nested functions) and
     479                 :      * we cannot get to deep recursion.
     480                 :      */
     481        15221160 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     482         6744948 :         MarkChildren(gcmarker, thing);
     483        15221160 : }
     484                 : 
     485                 : static void
     486                 : ScanShape(GCMarker *gcmarker, Shape *shape);
     487                 : 
     488                 : static void
     489        61932584 : PushMarkStack(GCMarker *gcmarker, Shape *thing)
     490                 : {
     491        61932584 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     492                 : 
     493                 :     /* We mark shapes directly rather than pushing on the stack. */
     494        61932584 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     495        12849709 :         ScanShape(gcmarker, thing);
     496        61932584 : }
     497                 : 
     498                 : static inline void
     499                 : ScanBaseShape(GCMarker *gcmarker, BaseShape *base);
     500                 : 
     501                 : static void
     502        91645809 : PushMarkStack(GCMarker *gcmarker, BaseShape *thing)
     503                 : {
     504        91645809 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     505                 : 
     506                 :     /* We mark base shapes directly rather than pushing on the stack. */
     507        91645809 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     508        14780129 :         ScanBaseShape(gcmarker, thing);
     509        91645809 : }
     510                 : 
     511                 : static void
     512        91517498 : ScanShape(GCMarker *gcmarker, Shape *shape)
     513                 : {
     514                 :   restart:
     515        91517498 :     PushMarkStack(gcmarker, shape->base());
     516                 : 
     517        91517498 :     const HeapId &id = shape->propidRef();
     518        91517498 :     if (JSID_IS_STRING(id))
     519        61059922 :         PushMarkStack(gcmarker, JSID_TO_STRING(id));
     520        30457576 :     else if (JS_UNLIKELY(JSID_IS_OBJECT(id)))
     521               0 :         PushMarkStack(gcmarker, JSID_TO_OBJECT(id));
     522                 : 
     523        91517498 :     shape = shape->previous();
     524        91517498 :     if (shape && shape->markIfUnmarked(gcmarker->getMarkColor()))
     525        78667789 :         goto restart;
     526        12849709 : }
     527                 : 
     528                 : static inline void
     529        14780129 : ScanBaseShape(GCMarker *gcmarker, BaseShape *base)
     530                 : {
     531        14780129 :     base->assertConsistency();
     532                 : 
     533        14780129 :     if (base->hasGetterObject())
     534         3385508 :         PushMarkStack(gcmarker, base->getterObject());
     535                 : 
     536        14780129 :     if (base->hasSetterObject())
     537          532214 :         PushMarkStack(gcmarker, base->setterObject());
     538                 : 
     539        14780129 :     if (JSObject *parent = base->getObjectParent())
     540        14254109 :         PushMarkStack(gcmarker, parent);
     541                 : 
     542                 :     /*
     543                 :      * All children of the owned base shape are consistent with its
     544                 :      * unowned one, thus we do not need to trace through children of the
     545                 :      * unowned base shape.
     546                 :      */
     547        14780129 :     if (base->isOwned()) {
     548         1556083 :         UnownedBaseShape *unowned = base->baseUnowned();
     549         1556083 :         JS_ASSERT(base->compartment() == unowned->compartment());
     550         1556083 :         unowned->markIfUnmarked(gcmarker->getMarkColor());
     551                 :     }
     552        14780129 : }
     553                 : 
     554                 : static inline void
     555       314936990 : ScanLinearString(GCMarker *gcmarker, JSLinearString *str)
     556                 : {
     557       314936990 :     JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, str);
     558       314936990 :     JS_ASSERT(str->isMarked());
     559                 : 
     560                 :     /*
     561                 :      * Add extra asserts to confirm the static type to detect incorrect string
     562                 :      * mutations.
     563                 :      */
     564       314936990 :     JS_ASSERT(str->JSString::isLinear());
     565       629946481 :     while (str->isDependent()) {
     566          496256 :         str = str->asDependent().base();
     567          496256 :         JS_ASSERT(str->JSString::isLinear());
     568          496256 :         JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, str);
     569          496256 :         if (!str->markIfUnmarked())
     570          423755 :             break;
     571                 :     }
     572       314936990 : }
     573                 : 
     574                 : /*
     575                 :  * The function tries to scan the whole rope tree using the marking stack as
     576                 :  * temporary storage. If that becomes full, the unscanned ropes are added to
     577                 :  * the delayed marking list. When the function returns, the marking stack is
     578                 :  * at the same depth as it was on entry. This way we avoid using tags when
     579                 :  * pushing ropes to the stack as ropes never leaks to other users of the
     580                 :  * stack. This also assumes that a rope can only point to other ropes or
     581                 :  * linear strings, it cannot refer to GC things of other types.
     582                 :  */
     583                 : static void
     584         2991248 : ScanRope(GCMarker *gcmarker, JSRope *rope)
     585                 : {
     586         2991248 :     ptrdiff_t savedPos = gcmarker->stack.position();
     587         7657748 :     for (;;) {
     588        10648996 :         JS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING);
     589        10648996 :         JS_ASSERT(rope->JSString::isRope());
     590        10648996 :         JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, rope);
     591        10648996 :         JS_ASSERT(rope->isMarked());
     592        10648996 :         JSRope *next = NULL;
     593                 : 
     594        10648996 :         JSString *right = rope->rightChild();
     595        10648996 :         if (right->markIfUnmarked()) {
     596         2360360 :             if (right->isLinear())
     597           51325 :                 ScanLinearString(gcmarker, &right->asLinear());
     598                 :             else
     599         2309035 :                 next = &right->asRope();
     600                 :         }
     601                 : 
     602        10648996 :         JSString *left = rope->leftChild();
     603        10648996 :         if (left->markIfUnmarked()) {
     604         5353264 :             if (left->isLinear()) {
     605            4551 :                 ScanLinearString(gcmarker, &left->asLinear());
     606                 :             } else {
     607                 :                 /*
     608                 :                  * When both children are ropes, set aside the right one to
     609                 :                  * scan it later.
     610                 :                  */
     611         5348713 :                 if (next && !gcmarker->stack.push(reinterpret_cast<uintptr_t>(next)))
     612               0 :                     gcmarker->delayMarkingChildren(next);
     613         5348713 :                 next = &left->asRope();
     614                 :             }
     615                 :         }
     616        10648996 :         if (next) {
     617         7657746 :             rope = next;
     618         2991250 :         } else if (savedPos != gcmarker->stack.position()) {
     619               2 :             JS_ASSERT(savedPos < gcmarker->stack.position());
     620               2 :             rope = reinterpret_cast<JSRope *>(gcmarker->stack.pop());
     621                 :         } else {
     622                 :             break;
     623                 :         }
     624                 :     }
     625         2991248 :     JS_ASSERT(savedPos == gcmarker->stack.position());
     626         2991248 :  }
     627                 : 
     628                 : static inline void
     629       317872362 : ScanString(GCMarker *gcmarker, JSString *str)
     630                 : {
     631       317872362 :     if (str->isLinear())
     632       314881114 :         ScanLinearString(gcmarker, &str->asLinear());
     633                 :     else
     634         2991248 :         ScanRope(gcmarker, &str->asRope());
     635       317872362 : }
     636                 : 
     637                 : static inline void
     638       412164769 : PushMarkStack(GCMarker *gcmarker, JSString *str)
     639                 : {
     640       412164769 :     JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, str);
     641                 : 
     642                 :     /*
     643                 :      * As string can only refer to other strings we fully scan its GC graph
     644                 :      * using the explicit stack when navigating the rope tree to avoid
     645                 :      * dealing with strings on the stack in drainMarkStack.
     646                 :      */
     647       412164769 :     if (str->markIfUnmarked())
     648       273036135 :         ScanString(gcmarker, str);
     649       412164769 : }
     650                 : 
     651                 : void
     652         3301222 : MarkChildren(JSTracer *trc, JSObject *obj)
     653                 : {
     654         3301222 :     obj->markChildren(trc);
     655         3301222 : }
     656                 : 
     657                 : static void
     658        17368244 : MarkChildren(JSTracer *trc, JSString *str)
     659                 : {
     660        17368244 :     if (str->isDependent())
     661            1019 :         str->asDependent().markChildren(trc);
     662        17367225 :     else if (str->isRope())
     663            2154 :         str->asRope().markChildren(trc);
     664        17368244 : }
     665                 : 
     666                 : static void
     667         6816458 : MarkChildren(JSTracer *trc, JSScript *script)
     668                 : {
     669         6816458 :     script->markChildren(trc);
     670         6816458 : }
     671                 : 
     672                 : static void
     673         3706062 : MarkChildren(JSTracer *trc, Shape *shape)
     674                 : {
     675         3706062 :     shape->markChildren(trc);
     676         3706062 : }
     677                 : 
     678                 : static void
     679         1145237 : MarkChildren(JSTracer *trc, BaseShape *base)
     680                 : {
     681         1145237 :     base->markChildren(trc);
     682         1145237 : }
     683                 : 
     684                 : /*
     685                 :  * This function is used by the cycle collector to trace through the
     686                 :  * children of a BaseShape (and its baseUnowned(), if any). The cycle
     687                 :  * collector does not directly care about BaseShapes, so only the
     688                 :  * getter, setter, and parent are marked. Furthermore, the parent is
     689                 :  * marked only if it isn't the same as prevParent, which will be
     690                 :  * updated to the current shape's parent.
     691                 :  */
     692                 : inline void
     693          840045 : MarkCycleCollectorChildren(JSTracer *trc, BaseShape *base, JSObject **prevParent)
     694                 : {
     695          840045 :     JS_ASSERT(base);
     696                 : 
     697                 :     /*
     698                 :      * The cycle collector does not need to trace unowned base shapes,
     699                 :      * as they have the same getter, setter and parent as the original
     700                 :      * base shape.
     701                 :      */
     702          840045 :     base->assertConsistency();
     703                 : 
     704          840045 :     if (base->hasGetterObject()) {
     705           11632 :         JSObject *tmp = base->getterObject();
     706           11632 :         MarkObjectUnbarriered(trc, &tmp, "getter");
     707           11632 :         JS_ASSERT(tmp == base->getterObject());
     708                 :     }
     709                 : 
     710          840045 :     if (base->hasSetterObject()) {
     711             470 :         JSObject *tmp = base->setterObject();
     712             470 :         MarkObjectUnbarriered(trc, &tmp, "setter");
     713             470 :         JS_ASSERT(tmp == base->setterObject());
     714                 :     }
     715                 : 
     716          840045 :     JSObject *parent = base->getObjectParent();
     717          840045 :     if (parent && parent != *prevParent) {
     718          296919 :         MarkObjectUnbarriered(trc, &parent, "parent");
     719          296919 :         JS_ASSERT(parent == base->getObjectParent());
     720          296919 :         *prevParent = parent;
     721                 :     }
     722          840045 : }
     723                 : 
     724                 : /*
     725                 :  * This function is used by the cycle collector to trace through a
     726                 :  * shape. The cycle collector does not care about shapes or base
     727                 :  * shapes, so those are not marked. Instead, any shapes or base shapes
     728                 :  * that are encountered have their children marked. Stack space is
     729                 :  * bounded. If two shapes in a row have the same parent pointer, the
     730                 :  * parent pointer will only be marked once.
     731                 :  */
     732                 : void
     733          344178 : MarkCycleCollectorChildren(JSTracer *trc, Shape *shape)
     734                 : {
     735          344178 :     JSObject *prevParent = NULL;
     736          840045 :     do {
     737          840045 :         MarkCycleCollectorChildren(trc, shape->base(), &prevParent);
     738          840045 :         MarkId(trc, &shape->propidRef(), "propid");
     739          840045 :         shape = shape->previous();
     740                 :     } while (shape);
     741          344178 : }
     742                 : 
     743                 : static void
     744         2100944 : ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
     745                 : {
     746         2100944 :     if (!type->singleton) {
     747         1998487 :         unsigned count = type->getPropertyCount();
     748         2005132 :         for (unsigned i = 0; i < count; i++) {
     749            6645 :             types::Property *prop = type->getProperty(i);
     750            6645 :             if (prop && JSID_IS_STRING(prop->id))
     751            3947 :                 PushMarkStack(gcmarker, JSID_TO_STRING(prop->id));
     752                 :         }
     753                 :     }
     754                 : 
     755         2100944 :     if (type->proto)
     756         2037630 :         PushMarkStack(gcmarker, type->proto);
     757                 : 
     758         2100944 :     if (type->newScript) {
     759               9 :         PushMarkStack(gcmarker, type->newScript->fun);
     760               9 :         PushMarkStack(gcmarker, type->newScript->shape);
     761                 :     }
     762                 : 
     763         2100944 :     if (type->interpretedFunction)
     764          179219 :         PushMarkStack(gcmarker, type->interpretedFunction);
     765                 : 
     766         2100944 :     if (type->singleton && !type->lazy())
     767           60300 :         PushMarkStack(gcmarker, type->singleton);
     768                 : 
     769         2100944 :     if (type->interpretedFunction)
     770          179219 :         PushMarkStack(gcmarker, type->interpretedFunction);
     771         2100944 : }
     772                 : 
     773                 : static void
     774          392205 : MarkChildren(JSTracer *trc, types::TypeObject *type)
     775                 : {
     776          392205 :     if (!type->singleton) {
     777          381253 :         unsigned count = type->getPropertyCount();
     778          383343 :         for (unsigned i = 0; i < count; i++) {
     779            2090 :             types::Property *prop = type->getProperty(i);
     780            2090 :             if (prop)
     781            2090 :                 MarkId(trc, &prop->id, "type_prop");
     782                 :         }
     783                 :     }
     784                 : 
     785          392205 :     if (type->proto)
     786          377751 :         MarkObject(trc, &type->proto, "type_proto");
     787                 : 
     788          392205 :     if (type->singleton && !type->lazy())
     789            7219 :         MarkObject(trc, &type->singleton, "type_singleton");
     790                 : 
     791          392205 :     if (type->newScript) {
     792             124 :         MarkObject(trc, &type->newScript->fun, "type_new_function");
     793             124 :         MarkShape(trc, &type->newScript->shape, "type_new_shape");
     794                 :     }
     795                 : 
     796          392205 :     if (type->interpretedFunction)
     797           32945 :         MarkObject(trc, &type->interpretedFunction, "type_function");
     798          392205 : }
     799                 : 
     800                 : #ifdef JS_HAS_XML_SUPPORT
     801                 : static void
     802            2520 : MarkChildren(JSTracer *trc, JSXML *xml)
     803                 : {
     804            2520 :     js_TraceXML(trc, xml);
     805            2520 : }
     806                 : #endif
     807                 : 
     808                 : template<typename T>
     809                 : void
     810               0 : PushArenaTyped(GCMarker *gcmarker, ArenaHeader *aheader)
     811                 : {
     812               0 :     for (CellIterUnderGC i(aheader); !i.done(); i.next())
     813               0 :         PushMarkStack(gcmarker, i.get<T>());
     814               0 : }
     815                 : 
     816                 : void
     817               0 : PushArena(GCMarker *gcmarker, ArenaHeader *aheader)
     818                 : {
     819               0 :     switch (MapAllocToTraceKind(aheader->getAllocKind())) {
     820                 :       case JSTRACE_OBJECT:
     821               0 :         PushArenaTyped<JSObject>(gcmarker, aheader);
     822               0 :         break;
     823                 : 
     824                 :       case JSTRACE_STRING:
     825               0 :         PushArenaTyped<JSString>(gcmarker, aheader);
     826               0 :         break;
     827                 : 
     828                 :       case JSTRACE_SCRIPT:
     829               0 :         PushArenaTyped<JSScript>(gcmarker, aheader);
     830               0 :         break;
     831                 : 
     832                 :       case JSTRACE_SHAPE:
     833               0 :         PushArenaTyped<js::Shape>(gcmarker, aheader);
     834               0 :         break;
     835                 : 
     836                 :       case JSTRACE_BASE_SHAPE:
     837               0 :         PushArenaTyped<js::BaseShape>(gcmarker, aheader);
     838               0 :         break;
     839                 : 
     840                 :       case JSTRACE_TYPE_OBJECT:
     841               0 :         PushArenaTyped<js::types::TypeObject>(gcmarker, aheader);
     842               0 :         break;
     843                 : 
     844                 : #if JS_HAS_XML_SUPPORT
     845                 :       case JSTRACE_XML:
     846               0 :         PushArenaTyped<JSXML>(gcmarker, aheader);
     847               0 :         break;
     848                 : #endif
     849                 :     }
     850               0 : }
     851                 : 
     852                 : } /* namespace gc */
     853                 : 
     854                 : using namespace js::gc;
     855                 : 
     856                 : struct SlotArrayLayout
     857                 : {
     858                 :     union {
     859                 :         HeapSlot *end;
     860                 :         js::Class *clasp;
     861                 :     };
     862                 :     union {
     863                 :         HeapSlot *start;
     864                 :         uintptr_t index;
     865                 :     };
     866                 :     JSObject *obj;
     867                 : 
     868                 :     static void staticAsserts() {
     869                 :         /* This should have the same layout as three mark stack items. */
     870                 :         JS_STATIC_ASSERT(sizeof(SlotArrayLayout) == 3 * sizeof(uintptr_t));
     871                 :     }
     872                 : };
     873                 : 
     874                 : /*
     875                 :  * During incremental GC, we return from drainMarkStack without having processed
     876                 :  * the entire stack. At that point, JS code can run and reallocate slot arrays
     877                 :  * that are stored on the stack. To prevent this from happening, we replace all
     878                 :  * ValueArrayTag stack items with SavedValueArrayTag. In the latter, slots
     879                 :  * pointers are replaced with slot indexes.
     880                 :  *
     881                 :  * We also replace the slot array end pointer (which can be derived from the obj
     882                 :  * pointer) with the object's class. During JS executation, array slowification
     883                 :  * can cause the layout of slots to change. We can observe that slowification
     884                 :  * happened if the class changed; in that case, we completely rescan the array.
     885                 :  */
     886                 : void
     887               0 : GCMarker::saveValueRanges()
     888                 : {
     889               0 :     for (uintptr_t *p = stack.tos; p > stack.stack; ) {
     890               0 :         uintptr_t tag = *--p & StackTagMask;
     891               0 :         if (tag == ValueArrayTag) {
     892               0 :             p -= 2;
     893               0 :             SlotArrayLayout *arr = reinterpret_cast<SlotArrayLayout *>(p);
     894               0 :             JSObject *obj = arr->obj;
     895                 : 
     896               0 :             if (obj->getClass() == &ArrayClass) {
     897               0 :                 HeapSlot *vp = obj->getDenseArrayElements();
     898               0 :                 JS_ASSERT(arr->start >= vp &&
     899               0 :                           arr->end == vp + obj->getDenseArrayInitializedLength());
     900               0 :                 arr->index = arr->start - vp;
     901                 :             } else {
     902               0 :                 HeapSlot *vp = obj->fixedSlots();
     903               0 :                 unsigned nfixed = obj->numFixedSlots();
     904               0 :                 if (arr->start == arr->end) {
     905               0 :                     arr->index = obj->slotSpan();
     906               0 :                 } if (arr->start >= vp && arr->start < vp + nfixed) {
     907               0 :                     JS_ASSERT(arr->end == vp + Min(nfixed, obj->slotSpan()));
     908               0 :                     arr->index = arr->start - vp;
     909                 :                 } else {
     910               0 :                     JS_ASSERT(arr->start >= obj->slots &&
     911               0 :                               arr->end == obj->slots + obj->slotSpan() - nfixed);
     912               0 :                     arr->index = (arr->start - obj->slots) + nfixed;
     913                 :                 }
     914                 :             }
     915               0 :             arr->clasp = obj->getClass();
     916               0 :             p[2] |= SavedValueArrayTag;
     917               0 :         } else if (tag == SavedValueArrayTag) {
     918               0 :             p -= 2;
     919                 :         }
     920                 :     }
     921               0 : }
     922                 : 
     923                 : JS_NEVER_INLINE bool
     924               0 : GCMarker::restoreValueArray(JSObject *obj, void **vpp, void **endp)
     925                 : {
     926               0 :     uintptr_t start = stack.pop();
     927               0 :     js::Class *clasp = reinterpret_cast<js::Class *>(stack.pop());
     928                 : 
     929               0 :     JS_ASSERT(obj->getClass() == clasp ||
     930               0 :               (clasp == &ArrayClass && obj->getClass() == &SlowArrayClass));
     931                 : 
     932               0 :     if (clasp == &ArrayClass) {
     933               0 :         if (obj->getClass() != &ArrayClass)
     934               0 :             return false;
     935                 : 
     936               0 :         uint32_t initlen = obj->getDenseArrayInitializedLength();
     937               0 :         HeapSlot *vp = obj->getDenseArrayElements();
     938               0 :         if (start < initlen) {
     939               0 :             *vpp = vp + start;
     940               0 :             *endp = vp + initlen;
     941                 :         } else {
     942                 :             /* The object shrunk, in which case no scanning is needed. */
     943               0 :             *vpp = *endp = vp;
     944                 :         }
     945                 :     } else {
     946               0 :         HeapSlot *vp = obj->fixedSlots();
     947               0 :         unsigned nfixed = obj->numFixedSlots();
     948               0 :         unsigned nslots = obj->slotSpan();
     949               0 :         if (start < nfixed) {
     950               0 :             *vpp = vp + start;
     951               0 :             *endp = vp + Min(nfixed, nslots);
     952               0 :         } else if (start < nslots) {
     953               0 :             *vpp = obj->slots + start - nfixed;
     954               0 :             *endp = obj->slots + nslots - nfixed;
     955                 :         } else {
     956                 :             /* The object shrunk, in which case no scanning is needed. */
     957               0 :             *vpp = *endp = obj->slots;
     958                 :         }
     959                 :     }
     960                 : 
     961               0 :     JS_ASSERT(*vpp <= *endp);
     962               0 :     return true;
     963                 : }
     964                 : 
     965                 : void
     966         2103464 : GCMarker::processMarkStackOther(uintptr_t tag, uintptr_t addr)
     967                 : {
     968         2103464 :     if (tag == TypeTag) {
     969         2100944 :         ScanTypeObject(this, reinterpret_cast<types::TypeObject *>(addr));
     970            2520 :     } else if (tag == SavedValueArrayTag) {
     971               0 :         JS_ASSERT(!(addr & Cell::CellMask));
     972               0 :         JSObject *obj = reinterpret_cast<JSObject *>(addr);
     973                 :         HeapValue *vp, *end;
     974               0 :         if (restoreValueArray(obj, (void **)&vp, (void **)&end))
     975               0 :             pushValueArray(obj, vp, end);
     976                 :         else
     977               0 :             pushObject(obj);
     978                 :     } else {
     979            2520 :         JS_ASSERT(tag == XmlTag);
     980            2520 :         MarkChildren(this, reinterpret_cast<JSXML *>(addr));
     981                 :     }
     982         2103464 : }
     983                 : 
     984                 : inline void
     985        65400715 : GCMarker::processMarkStackTop(SliceBudget &budget)
     986                 : {
     987                 :     /*
     988                 :      * The function uses explicit goto and implements the scanning of the
     989                 :      * object directly. It allows to eliminate the tail recursion and
     990                 :      * significantly improve the marking performance, see bug 641025.
     991                 :      */
     992                 :     HeapSlot *vp, *end;
     993                 :     JSObject *obj;
     994                 : 
     995        65400715 :     uintptr_t addr = stack.pop();
     996        65400715 :     uintptr_t tag = addr & StackTagMask;
     997        65400715 :     addr &= ~StackTagMask;
     998                 : 
     999        65400715 :     if (tag == ValueArrayTag) {
    1000                 :         JS_STATIC_ASSERT(ValueArrayTag == 0);
    1001        46091812 :         JS_ASSERT(!(addr & Cell::CellMask));
    1002        46091812 :         obj = reinterpret_cast<JSObject *>(addr);
    1003        46091812 :         uintptr_t addr2 = stack.pop();
    1004        46091812 :         uintptr_t addr3 = stack.pop();
    1005        46091812 :         JS_ASSERT(addr2 <= addr3);
    1006        46091812 :         JS_ASSERT((addr3 - addr2) % sizeof(Value) == 0);
    1007        46091812 :         vp = reinterpret_cast<HeapSlot *>(addr2);
    1008        46091812 :         end = reinterpret_cast<HeapSlot *>(addr3);
    1009        46091812 :         goto scan_value_array;
    1010                 :     }
    1011                 : 
    1012        19308903 :     if (tag == ObjectTag) {
    1013        17205439 :         obj = reinterpret_cast<JSObject *>(addr);
    1014        17205439 :         JS_COMPARTMENT_ASSERT(runtime, obj);
    1015        17205439 :         goto scan_obj;
    1016                 :     }
    1017                 : 
    1018         2103464 :     processMarkStackOther(tag, addr);
    1019         2103464 :     return;
    1020                 : 
    1021                 :   scan_value_array:
    1022       100323887 :     JS_ASSERT(vp <= end);
    1023       375287310 :     while (vp != end) {
    1024       211674549 :         const Value &v = *vp++;
    1025       211674549 :         if (v.isString()) {
    1026        84532698 :             JSString *str = v.toString();
    1027        84532698 :             JS_COMPARTMENT_ASSERT_STR(runtime, str);
    1028        84532698 :             if (str->markIfUnmarked())
    1029        44836227 :                 ScanString(this, str);
    1030       127141851 :         } else if (v.isObject()) {
    1031        47964888 :             JSObject *obj2 = &v.toObject();
    1032        47964888 :             JS_COMPARTMENT_ASSERT(runtime, obj2);
    1033        47964888 :             if (obj2->markIfUnmarked(getMarkColor())) {
    1034        37035013 :                 pushValueArray(obj, vp, end);
    1035        37035013 :                 obj = obj2;
    1036        37035013 :                 goto scan_obj;
    1037                 :             }
    1038                 :         }
    1039                 :     }
    1040        63288874 :     return;
    1041                 : 
    1042                 :   scan_obj:
    1043                 :     {
    1044        54240452 :         JS_COMPARTMENT_ASSERT(runtime, obj);
    1045                 : 
    1046        54240452 :         budget.step();
    1047        54240452 :         if (budget.isOverBudget()) {
    1048               0 :             pushObject(obj);
    1049               0 :             return;
    1050                 :         }
    1051                 : 
    1052        54240452 :         types::TypeObject *type = obj->typeFromGC();
    1053        54240452 :         PushMarkStack(this, type);
    1054                 : 
    1055        54240452 :         Shape *shape = obj->lastProperty();
    1056        54240452 :         PushMarkStack(this, shape);
    1057                 : 
    1058                 :         /* Call the trace hook if necessary. */
    1059        54240452 :         Class *clasp = shape->getObjectClass();
    1060        54240452 :         if (clasp->trace) {
    1061        47374933 :             if (clasp == &ArrayClass) {
    1062         1325027 :                 JS_ASSERT(!shape->isNative());
    1063         1325027 :                 vp = obj->getDenseArrayElements();
    1064         1325027 :                 end = vp + obj->getDenseArrayInitializedLength();
    1065         1325027 :                 goto scan_value_array;
    1066                 :             } else {
    1067               0 :                 JS_ASSERT_IF(runtime->gcIncrementalState != NO_INCREMENTAL,
    1068        46049906 :                              clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
    1069                 :             }
    1070        46049906 :             clasp->trace(this, obj);
    1071                 :         }
    1072                 : 
    1073        52915425 :         if (!shape->isNative())
    1074            8377 :             return;
    1075                 : 
    1076        52907048 :         unsigned nslots = obj->slotSpan();
    1077        52907048 :         vp = obj->fixedSlots();
    1078        52907048 :         if (obj->slots) {
    1079         9056799 :             unsigned nfixed = obj->numFixedSlots();
    1080         9056799 :             if (nslots > nfixed) {
    1081         9056799 :                 pushValueArray(obj, vp, vp + nfixed);
    1082         9056799 :                 vp = obj->slots;
    1083         9056799 :                 end = vp + (nslots - nfixed);
    1084         9056799 :                 goto scan_value_array;
    1085                 :             }
    1086                 :         }
    1087        43850249 :         JS_ASSERT(nslots <= obj->numFixedSlots());
    1088        43850249 :         end = vp + nslots;
    1089        43850249 :         goto scan_value_array;
    1090                 :     }
    1091                 : }
    1092                 : 
    1093                 : bool
    1094          102520 : GCMarker::drainMarkStack(SliceBudget &budget)
    1095                 : {
    1096                 : #ifdef DEBUG
    1097          102520 :     JSRuntime *rt = runtime;
    1098                 : 
    1099                 :     struct AutoCheckCompartment {
    1100                 :         JSRuntime *runtime;
    1101          102520 :         AutoCheckCompartment(JSRuntime *rt) : runtime(rt) {
    1102          102520 :             runtime->gcCheckCompartment = runtime->gcCurrentCompartment;
    1103          102520 :         }
    1104          102520 :         ~AutoCheckCompartment() { runtime->gcCheckCompartment = NULL; }
    1105          205040 :     } acc(rt);
    1106                 : #endif
    1107                 : 
    1108          102520 :     if (budget.isOverBudget())
    1109               0 :         return false;
    1110                 : 
    1111               0 :     for (;;) {
    1112        65605755 :         while (!stack.isEmpty()) {
    1113        65400715 :             processMarkStackTop(budget);
    1114        65400715 :             if (budget.isOverBudget()) {
    1115               0 :                 saveValueRanges();
    1116               0 :                 return false;
    1117                 :             }
    1118                 :         }
    1119                 : 
    1120          102520 :         if (!hasDelayedChildren())
    1121                 :             break;
    1122                 : 
    1123                 :         /*
    1124                 :          * Mark children of things that caused too deep recursion during the
    1125                 :          * above tracing. Don't do this until we're done with everything
    1126                 :          * else.
    1127                 :          */
    1128               0 :         if (!markDelayedChildren(budget)) {
    1129               0 :             saveValueRanges();
    1130               0 :             return false;
    1131                 :         }
    1132                 :     }
    1133                 : 
    1134          102520 :     return true;
    1135                 : }
    1136                 : 
    1137                 : void
    1138        25984480 : TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind)
    1139                 : {
    1140        25984480 :     switch (kind) {
    1141                 :       case JSTRACE_OBJECT:
    1142         3301222 :         MarkChildren(trc, static_cast<JSObject *>(thing));
    1143         3301222 :         break;
    1144                 : 
    1145                 :       case JSTRACE_STRING:
    1146        17368244 :         MarkChildren(trc, static_cast<JSString *>(thing));
    1147        17368244 :         break;
    1148                 : 
    1149                 :       case JSTRACE_SCRIPT:
    1150           71510 :         MarkChildren(trc, static_cast<JSScript *>(thing));
    1151           71510 :         break;
    1152                 : 
    1153                 :       case JSTRACE_SHAPE:
    1154         3706062 :         MarkChildren(trc, static_cast<Shape *>(thing));
    1155         3706062 :         break;
    1156                 : 
    1157                 :       case JSTRACE_BASE_SHAPE:
    1158         1145237 :         MarkChildren(trc, static_cast<BaseShape *>(thing));
    1159         1145237 :         break;
    1160                 : 
    1161                 :       case JSTRACE_TYPE_OBJECT:
    1162          392205 :         MarkChildren(trc, (types::TypeObject *)thing);
    1163          392205 :         break;
    1164                 : 
    1165                 : #if JS_HAS_XML_SUPPORT
    1166                 :       case JSTRACE_XML:
    1167               0 :         MarkChildren(trc, static_cast<JSXML *>(thing));
    1168               0 :         break;
    1169                 : #endif
    1170                 :     }
    1171        25984480 : }
    1172                 : 
    1173                 : void
    1174         8631512 : CallTracer(JSTracer *trc, void *thing, JSGCTraceKind kind)
    1175                 : {
    1176         8631512 :     JS_ASSERT(thing);
    1177         8631512 :     MarkKind(trc, thing, kind);
    1178         8631512 : }
    1179                 : 
    1180                 : } /* namespace js */

Generated by: LCOV version 1.7