LCOV - code coverage report
Current view: directory - js/src - jsgcmark.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 569 467 82.1 %
Date: 2012-04-07 Functions: 227 141 62.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       263204738 : CheckMarkedThing(JSTracer *trc, T *thing)
      77                 : {
      78       263204738 :     JS_ASSERT(trc);
      79       263204738 :     JS_ASSERT(thing);
      80       263204738 :     JS_ASSERT(thing->compartment());
      81       263204738 :     JS_ASSERT(thing->compartment()->rt == trc->runtime);
      82       263204738 :     JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
      83                 : 
      84       526409476 :     DebugOnly<JSRuntime *> rt = trc->runtime;
      85                 : 
      86       263204738 :     JS_ASSERT_IF(thing->compartment()->requireGCTracer(), IS_GC_MARKING_TRACER(trc));
      87                 : 
      88       263204738 :     JS_ASSERT(thing->isAligned());
      89                 : 
      90       263204738 :     JS_ASSERT_IF(rt->gcStrictCompartmentChecking,
      91                 :                  thing->compartment()->isCollecting() ||
      92                 :                  thing->compartment() == rt->atomsCompartment);
      93       263204738 : }
      94                 : 
      95                 : template<typename T>
      96                 : void
      97       263204738 : MarkInternal(JSTracer *trc, T **thingp)
      98                 : {
      99       263204738 :     JS_ASSERT(thingp);
     100       263204738 :     T *thing = *thingp;
     101                 : 
     102       263204738 :     CheckMarkedThing(trc, thing);
     103                 : 
     104                 :     /*
     105                 :      * Don't mark things outside a compartment if we are in a per-compartment
     106                 :      * GC.
     107                 :      */
     108       263204738 :     if (!trc->callback) {
     109       222684879 :         if (thing->compartment()->isCollecting())
     110       221754708 :             PushMarkStack(static_cast<GCMarker *>(trc), thing);
     111                 :     } else {
     112        40519859 :         trc->callback(trc, (void **)thingp, GetGCThingTraceKind(thing));
     113                 :     }
     114                 : 
     115                 : #ifdef DEBUG
     116       263204738 :     trc->debugPrinter = NULL;
     117       263204738 :     trc->debugPrintArg = NULL;
     118                 : #endif
     119       263204738 : }
     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       196762884 : MarkUnbarriered(JSTracer *trc, T **thingp, const char *name)
     130                 : {
     131       196762884 :     JS_SET_TRACING_NAME(trc, name);
     132       196762884 :     MarkInternal(trc, thingp);
     133       196762884 : }
     134                 : 
     135                 : template <typename T>
     136                 : static void
     137        33959951 : Mark(JSTracer *trc, HeapPtr<T> *thing, const char *name)
     138                 : {
     139        33959951 :     JS_SET_TRACING_NAME(trc, name);
     140        33959951 :     MarkInternal(trc, thing->unsafeGet());
     141        33959951 : }
     142                 : 
     143                 : template <typename T>
     144                 : static void
     145        11002695 : MarkRoot(JSTracer *trc, T **thingp, const char *name)
     146                 : {
     147        11002695 :     JS_ROOT_MARKING_ASSERT(trc);
     148        11002695 :     JS_SET_TRACING_NAME(trc, name);
     149        11002695 :     MarkInternal(trc, thingp);
     150        11002695 : }
     151                 : 
     152                 : template <typename T>
     153                 : static void
     154           26674 : MarkRange(JSTracer *trc, size_t len, HeapPtr<T> *vec, const char *name)
     155                 : {
     156           73620 :     for (size_t i = 0; i < len; ++i) {
     157           46946 :         if (vec[i].get()) {
     158           46946 :             JS_SET_TRACING_INDEX(trc, name, i);
     159           46946 :             MarkInternal(trc, vec[i].unsafeGet());
     160                 :         }
     161                 :     }
     162           26674 : }
     163                 : 
     164                 : template <typename T>
     165                 : static void
     166            1107 : MarkRootRange(JSTracer *trc, size_t len, T **vec, const char *name)
     167                 : {
     168            1107 :     JS_ROOT_MARKING_ASSERT(trc);
     169            7388 :     for (size_t i = 0; i < len; ++i) {
     170            6281 :         JS_SET_TRACING_INDEX(trc, name, i);
     171            6281 :         MarkInternal(trc, &vec[i]);
     172                 :     }
     173            1107 : }
     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         3673328 : DeclMarkerImpl(BaseShape, BaseShape)
     205           34789 : DeclMarkerImpl(BaseShape, UnownedBaseShape)
     206            1182 : DeclMarkerImpl(Object, ArgumentsObject)
     207           67363 : DeclMarkerImpl(Object, GlobalObject)
     208         3124747 : DeclMarkerImpl(Object, JSObject)
     209          697116 : DeclMarkerImpl(Object, JSFunction)
     210          979079 : DeclMarkerImpl(Script, JSScript)
     211         6172615 : DeclMarkerImpl(Shape, Shape)
     212       215367744 : DeclMarkerImpl(String, JSAtom)
     213          139350 : DeclMarkerImpl(String, JSString)
     214         8615092 : DeclMarkerImpl(String, JSFlatString)
     215            1243 : DeclMarkerImpl(String, JSLinearString)
     216         2879428 : DeclMarkerImpl(TypeObject, types::TypeObject)
     217                 : #if JS_HAS_XML_SUPPORT
     218             235 : DeclMarkerImpl(XML, JSXML)
     219                 : #endif
     220                 : 
     221                 : /*** Externally Typed Marking ***/
     222                 : 
     223                 : void
     224        18137003 : MarkKind(JSTracer *trc, void **thingp, JSGCTraceKind kind)
     225                 : {
     226        18137003 :     JS_ASSERT(thingp);
     227        18137003 :     JS_ASSERT(*thingp);
     228        18137003 :     JS_ASSERT(kind == GetGCThingTraceKind(*thingp));
     229        18137003 :     switch (kind) {
     230                 :       case JSTRACE_OBJECT:
     231        12851560 :         MarkInternal(trc, reinterpret_cast<JSObject **>(thingp));
     232        12851560 :         break;
     233                 :       case JSTRACE_STRING:
     234         2044711 :         MarkInternal(trc, reinterpret_cast<JSString **>(thingp));
     235         2044711 :         break;
     236                 :       case JSTRACE_SCRIPT:
     237         2170865 :         MarkInternal(trc, reinterpret_cast<JSScript **>(thingp));
     238         2170865 :         break;
     239                 :       case JSTRACE_SHAPE:
     240          928849 :         MarkInternal(trc, reinterpret_cast<Shape **>(thingp));
     241          928849 :         break;
     242                 :       case JSTRACE_BASE_SHAPE:
     243          118660 :         MarkInternal(trc, reinterpret_cast<BaseShape **>(thingp));
     244          118660 :         break;
     245                 :       case JSTRACE_TYPE_OBJECT:
     246           22304 :         MarkInternal(trc, reinterpret_cast<types::TypeObject **>(thingp));
     247           22304 :         break;
     248                 : #if JS_HAS_XML_SUPPORT
     249                 :       case JSTRACE_XML:
     250              54 :         MarkInternal(trc, reinterpret_cast<JSXML **>(thingp));
     251              54 :         break;
     252                 : #endif
     253                 :     }
     254        18137003 : }
     255                 : 
     256                 : void
     257           22828 : MarkGCThingRoot(JSTracer *trc, void **thingp, const char *name)
     258                 : {
     259           22828 :     JS_ROOT_MARKING_ASSERT(trc);
     260           22828 :     JS_SET_TRACING_NAME(trc, name);
     261           22828 :     JS_ASSERT(thingp);
     262           22828 :     if (!*thingp)
     263               0 :         return;
     264           22828 :     MarkKind(trc, thingp, GetGCThingTraceKind(*thingp));
     265                 : }
     266                 : 
     267                 : /*** ID Marking ***/
     268                 : 
     269                 : static inline void
     270         3730945 : MarkIdInternal(JSTracer *trc, jsid *id)
     271                 : {
     272         3730945 :     if (JSID_IS_STRING(*id)) {
     273         3187372 :         JSString *str = JSID_TO_STRING(*id);
     274         3187372 :         MarkInternal(trc, &str);
     275         3187372 :         *id = ATOM_TO_JSID(reinterpret_cast<JSAtom *>(str));
     276          543573 :     } else if (JS_UNLIKELY(JSID_IS_OBJECT(*id))) {
     277               0 :         JSObject *obj = JSID_TO_OBJECT(*id);
     278               0 :         MarkInternal(trc, &obj);
     279               0 :         *id = OBJECT_TO_JSID(obj);
     280                 :     }
     281         3730945 : }
     282                 : 
     283                 : void
     284         3672790 : MarkId(JSTracer *trc, HeapId *id, const char *name)
     285                 : {
     286         3672790 :     JS_SET_TRACING_NAME(trc, name);
     287         3672790 :     MarkIdInternal(trc, id->unsafeGet());
     288         3672790 : }
     289                 : 
     290                 : void
     291               0 : MarkIdRoot(JSTracer *trc, jsid *id, const char *name)
     292                 : {
     293               0 :     JS_ROOT_MARKING_ASSERT(trc);
     294               0 :     JS_SET_TRACING_NAME(trc, name);
     295               0 :     MarkIdInternal(trc, id);
     296               0 : }
     297                 : 
     298                 : void
     299               0 : MarkIdRange(JSTracer *trc, size_t len, HeapId *vec, const char *name)
     300                 : {
     301               0 :     for (size_t i = 0; i < len; ++i) {
     302               0 :         JS_SET_TRACING_INDEX(trc, name, i);
     303               0 :         MarkIdInternal(trc, vec[i].unsafeGet());
     304                 :     }
     305               0 : }
     306                 : 
     307                 : void
     308            1242 : MarkIdRootRange(JSTracer *trc, size_t len, jsid *vec, const char *name)
     309                 : {
     310            1242 :     JS_ROOT_MARKING_ASSERT(trc);
     311           59397 :     for (size_t i = 0; i < len; ++i) {
     312           58155 :         JS_SET_TRACING_INDEX(trc, name, i);
     313           58155 :         MarkIdInternal(trc, &vec[i]);
     314                 :     }
     315            1242 : }
     316                 : 
     317                 : /*** Value Marking ***/
     318                 : 
     319                 : static inline void
     320        13855200 : MarkValueInternal(JSTracer *trc, Value *v)
     321                 : {
     322        13855200 :     if (v->isMarkable()) {
     323         6957567 :         JS_ASSERT(v->toGCThing());
     324         6957567 :         void *thing = v->toGCThing();
     325         6957567 :         MarkKind(trc, &thing, v->gcKind());
     326         6957567 :         if (v->isString())
     327         1575411 :             v->setString((JSString *)thing);
     328                 :         else
     329         5382156 :             v->setObjectOrNull((JSObject *)thing);
     330                 :     }
     331        13855200 : }
     332                 : 
     333                 : void
     334           13572 : MarkValue(JSTracer *trc, HeapValue *v, const char *name)
     335                 : {
     336           13572 :     JS_SET_TRACING_NAME(trc, name);
     337           13572 :     MarkValueInternal(trc, v->unsafeGet());
     338           13572 : }
     339                 : 
     340                 : void
     341           31718 : MarkValueRoot(JSTracer *trc, Value *v, const char *name)
     342                 : {
     343           31718 :     JS_ROOT_MARKING_ASSERT(trc);
     344           31718 :     JS_SET_TRACING_NAME(trc, name);
     345           31718 :     MarkValueInternal(trc, v);
     346           31718 : }
     347                 : 
     348                 : void
     349          829305 : MarkValueRange(JSTracer *trc, size_t len, HeapValue *vec, const char *name)
     350                 : {
     351         2480993 :     for (size_t i = 0; i < len; ++i) {
     352         1651688 :         JS_SET_TRACING_INDEX(trc, name, i);
     353         1651688 :         MarkValueInternal(trc, vec[i].unsafeGet());
     354                 :     }
     355          829305 : }
     356                 : 
     357                 : void
     358          634041 : MarkValueRootRange(JSTracer *trc, size_t len, Value *vec, const char *name)
     359                 : {
     360          634041 :     JS_ROOT_MARKING_ASSERT(trc);
     361         3825885 :     for (size_t i = 0; i < len; ++i) {
     362         3191844 :         JS_SET_TRACING_INDEX(trc, name, i);
     363         3191844 :         MarkValueInternal(trc, &vec[i]);
     364                 :     }
     365          634041 : }
     366                 : 
     367                 : /*** Slot Marking ***/
     368                 : 
     369                 : void
     370           85506 : MarkSlot(JSTracer *trc, HeapSlot *s, const char *name)
     371                 : {
     372           85506 :     JS_SET_TRACING_NAME(trc, name);
     373           85506 :     MarkValueInternal(trc, s->unsafeGet());
     374           85506 : }
     375                 : 
     376                 : void
     377            5528 : MarkArraySlots(JSTracer *trc, size_t len, HeapSlot *vec, const char *name)
     378                 : {
     379            9694 :     for (size_t i = 0; i < len; ++i) {
     380            4166 :         JS_SET_TRACING_INDEX(trc, name, i);
     381            4166 :         MarkValueInternal(trc, vec[i].unsafeGet());
     382                 :     }
     383            5528 : }
     384                 : 
     385                 : void
     386         2840717 : MarkObjectSlots(JSTracer *trc, JSObject *obj, uint32_t start, uint32_t nslots)
     387                 : {
     388         2840717 :     JS_ASSERT(obj->isNative());
     389        11110882 :     for (uint32_t i = start; i < (start + nslots); ++i) {
     390         8270165 :         JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i);
     391         8270165 :         MarkValueInternal(trc, obj->nativeGetSlotRef(i).unsafeGet());
     392                 :     }
     393         2840717 : }
     394                 : 
     395                 : void
     396            2597 : MarkCrossCompartmentObjectUnbarriered(JSTracer *trc, JSObject **obj, const char *name)
     397                 : {
     398            2597 :     if (IS_GC_MARKING_TRACER(trc) && !(*obj)->compartment()->isCollecting())
     399             135 :         return;
     400                 : 
     401            2462 :     MarkObjectUnbarriered(trc, obj, name);
     402                 : }
     403                 : 
     404                 : void
     405            1152 : MarkCrossCompartmentScriptUnbarriered(JSTracer *trc, JSScript **script, const char *name)
     406                 : {
     407            1152 :     if (IS_GC_MARKING_TRACER(trc) && !(*script)->compartment()->isCollecting())
     408              72 :         return;
     409                 : 
     410            1080 :     MarkScriptUnbarriered(trc, script, name);
     411                 : }
     412                 : 
     413                 : void
     414          171935 : MarkCrossCompartmentSlot(JSTracer *trc, HeapSlot *s, const char *name)
     415                 : {
     416          171935 :     if (s->isMarkable()) {
     417           85951 :         Cell *cell = (Cell *)s->toGCThing();
     418           85951 :         if (IS_GC_MARKING_TRACER(trc) && !cell->compartment()->isCollecting())
     419             498 :             return;
     420                 : 
     421           85453 :         MarkSlot(trc, s, name);
     422                 :     }
     423                 : }
     424                 : 
     425                 : /*** Special Marking ***/
     426                 : 
     427                 : void
     428          101606 : MarkObject(JSTracer *trc, HeapPtr<GlobalObject, JSScript *> *thingp, const char *name)
     429                 : {
     430          101606 :     JS_SET_TRACING_NAME(trc, name);
     431          101606 :     MarkInternal(trc, thingp->unsafeGet());
     432          101606 : }
     433                 : 
     434                 : void
     435          606541 : MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name)
     436                 : {
     437          606541 :     JS_SET_TRACING_NAME(trc, name);
     438          606541 :     MarkValueInternal(trc, v);
     439          606541 : }
     440                 : 
     441                 : /*** Push Mark Stack ***/
     442                 : 
     443                 : #define JS_COMPARTMENT_ASSERT(rt, thing)                                \
     444                 :     JS_ASSERT((thing)->compartment()->isCollecting())
     445                 : 
     446                 : #define JS_COMPARTMENT_ASSERT_STR(rt, thing)                            \
     447                 :     JS_ASSERT((thing)->compartment()->isCollecting() ||                 \
     448                 :               (thing)->compartment() == (rt)->atomsCompartment);
     449                 : 
     450                 : static void
     451             246 : PushMarkStack(GCMarker *gcmarker, JSXML *thing)
     452                 : {
     453             246 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     454                 : 
     455             246 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     456             194 :         gcmarker->pushXML(thing);
     457             246 : }
     458                 : 
     459                 : static void
     460        19392247 : PushMarkStack(GCMarker *gcmarker, JSObject *thing)
     461                 : {
     462        19392247 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     463                 : 
     464        19392247 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     465         3632213 :         gcmarker->pushObject(thing);
     466        19392247 : }
     467                 : 
     468                 : static void
     469          699225 : PushMarkStack(GCMarker *gcmarker, JSFunction *thing)
     470                 : {
     471          699225 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     472                 : 
     473          699225 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     474           65563 :         gcmarker->pushObject(thing);
     475          699225 : }
     476                 : 
     477                 : static void
     478        16516391 : PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing)
     479                 : {
     480        16516391 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     481                 : 
     482        16516391 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     483          422962 :         gcmarker->pushType(thing);
     484        16516391 : }
     485                 : 
     486                 : static void
     487                 : MarkChildren(JSTracer *trc, JSScript *script);
     488                 : 
     489                 : static void
     490         3114002 : PushMarkStack(GCMarker *gcmarker, JSScript *thing)
     491                 : {
     492         3114002 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     493                 : 
     494                 :     /*
     495                 :      * We mark scripts directly rather than pushing on the stack as they can
     496                 :      * refer to other scripts only indirectly (like via nested functions) and
     497                 :      * we cannot get to deep recursion.
     498                 :      */
     499         3114002 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     500          127210 :         MarkChildren(gcmarker, thing);
     501         3114002 : }
     502                 : 
     503                 : static void
     504                 : ScanShape(GCMarker *gcmarker, Shape *shape);
     505                 : 
     506                 : static void
     507        17523634 : PushMarkStack(GCMarker *gcmarker, Shape *thing)
     508                 : {
     509        17523634 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     510                 : 
     511                 :     /* We mark shapes directly rather than pushing on the stack. */
     512        17523634 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     513         3052445 :         ScanShape(gcmarker, thing);
     514        17523634 : }
     515                 : 
     516                 : static inline void
     517                 : ScanBaseShape(GCMarker *gcmarker, BaseShape *base);
     518                 : 
     519                 : static void
     520        18735431 : PushMarkStack(GCMarker *gcmarker, BaseShape *thing)
     521                 : {
     522        18735431 :     JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing);
     523                 : 
     524                 :     /* We mark base shapes directly rather than pushing on the stack. */
     525        18735431 :     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
     526         6027805 :         ScanBaseShape(gcmarker, thing);
     527        18735431 : }
     528                 : 
     529                 : static void
     530        18614288 : ScanShape(GCMarker *gcmarker, Shape *shape)
     531                 : {
     532                 :   restart:
     533        18614288 :     PushMarkStack(gcmarker, shape->base());
     534                 : 
     535        18614288 :     const HeapId &id = shape->propidRef();
     536        18614288 :     if (JSID_IS_STRING(id))
     537        15468539 :         PushMarkStack(gcmarker, JSID_TO_STRING(id));
     538         3145749 :     else if (JS_UNLIKELY(JSID_IS_OBJECT(id)))
     539               0 :         PushMarkStack(gcmarker, JSID_TO_OBJECT(id));
     540                 : 
     541        18614288 :     shape = shape->previous();
     542        18614288 :     if (shape && shape->markIfUnmarked(gcmarker->getMarkColor()))
     543        15561843 :         goto restart;
     544         3052445 : }
     545                 : 
     546                 : static inline void
     547         6027805 : ScanBaseShape(GCMarker *gcmarker, BaseShape *base)
     548                 : {
     549         6027805 :     base->assertConsistency();
     550                 : 
     551         6027805 :     if (base->hasGetterObject())
     552         1797528 :         PushMarkStack(gcmarker, base->getterObject());
     553                 : 
     554         6027805 :     if (base->hasSetterObject())
     555          306980 :         PushMarkStack(gcmarker, base->setterObject());
     556                 : 
     557         6027805 :     if (JSObject *parent = base->getObjectParent())
     558         5889041 :         PushMarkStack(gcmarker, parent);
     559                 : 
     560                 :     /*
     561                 :      * All children of the owned base shape are consistent with its
     562                 :      * unowned one, thus we do not need to trace through children of the
     563                 :      * unowned base shape.
     564                 :      */
     565         6027805 :     if (base->isOwned()) {
     566          376548 :         UnownedBaseShape *unowned = base->baseUnowned();
     567          376548 :         JS_ASSERT(base->compartment() == unowned->compartment());
     568          376548 :         unowned->markIfUnmarked(gcmarker->getMarkColor());
     569                 :     }
     570         6027805 : }
     571                 : 
     572                 : static inline void
     573       197206293 : ScanLinearString(GCMarker *gcmarker, JSLinearString *str)
     574                 : {
     575       197206293 :     JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, str);
     576       197206293 :     JS_ASSERT(str->isMarked());
     577                 : 
     578                 :     /*
     579                 :      * Add extra asserts to confirm the static type to detect incorrect string
     580                 :      * mutations.
     581                 :      */
     582       197206293 :     JS_ASSERT(str->JSString::isLinear());
     583       394467721 :     while (str->isDependent()) {
     584          470891 :         str = str->asDependent().base();
     585          470891 :         JS_ASSERT(str->JSString::isLinear());
     586          470891 :         JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, str);
     587          470891 :         if (!str->markIfUnmarked())
     588          415756 :             break;
     589                 :     }
     590       197206293 : }
     591                 : 
     592                 : /*
     593                 :  * The function tries to scan the whole rope tree using the marking stack as
     594                 :  * temporary storage. If that becomes full, the unscanned ropes are added to
     595                 :  * the delayed marking list. When the function returns, the marking stack is
     596                 :  * at the same depth as it was on entry. This way we avoid using tags when
     597                 :  * pushing ropes to the stack as ropes never leaks to other users of the
     598                 :  * stack. This also assumes that a rope can only point to other ropes or
     599                 :  * linear strings, it cannot refer to GC things of other types.
     600                 :  */
     601                 : static void
     602         1928175 : ScanRope(GCMarker *gcmarker, JSRope *rope)
     603                 : {
     604         1928175 :     ptrdiff_t savedPos = gcmarker->stack.position();
     605         8054957 :     for (;;) {
     606         9983132 :         JS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING);
     607         9983132 :         JS_ASSERT(rope->JSString::isRope());
     608         9983132 :         JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, rope);
     609         9983132 :         JS_ASSERT(rope->isMarked());
     610         9983132 :         JSRope *next = NULL;
     611                 : 
     612         9983132 :         JSString *right = rope->rightChild();
     613         9983132 :         if (right->markIfUnmarked()) {
     614         3027045 :             if (right->isLinear())
     615             410 :                 ScanLinearString(gcmarker, &right->asLinear());
     616                 :             else
     617         3026635 :                 next = &right->asRope();
     618                 :         }
     619                 : 
     620         9983132 :         JSString *left = rope->leftChild();
     621         9983132 :         if (left->markIfUnmarked()) {
     622         5028515 :             if (left->isLinear()) {
     623             193 :                 ScanLinearString(gcmarker, &left->asLinear());
     624                 :             } else {
     625                 :                 /*
     626                 :                  * When both children are ropes, set aside the right one to
     627                 :                  * scan it later.
     628                 :                  */
     629         5028322 :                 if (next && !gcmarker->stack.push(reinterpret_cast<uintptr_t>(next)))
     630               0 :                     gcmarker->delayMarkingChildren(next);
     631         5028322 :                 next = &left->asRope();
     632                 :             }
     633                 :         }
     634         9983132 :         if (next) {
     635         8054957 :             rope = next;
     636         1928175 :         } else if (savedPos != gcmarker->stack.position()) {
     637               0 :             JS_ASSERT(savedPos < gcmarker->stack.position());
     638               0 :             rope = reinterpret_cast<JSRope *>(gcmarker->stack.pop());
     639                 :         } else {
     640                 :             break;
     641                 :         }
     642                 :     }
     643         1928175 :     JS_ASSERT(savedPos == gcmarker->stack.position());
     644         1928175 :  }
     645                 : 
     646                 : static inline void
     647       199133865 : ScanString(GCMarker *gcmarker, JSString *str)
     648                 : {
     649       199133865 :     if (str->isLinear())
     650       197205690 :         ScanLinearString(gcmarker, &str->asLinear());
     651                 :     else
     652         1928175 :         ScanRope(gcmarker, &str->asRope());
     653       199133865 : }
     654                 : 
     655                 : static inline void
     656       221311991 : PushMarkStack(GCMarker *gcmarker, JSString *str)
     657                 : {
     658       221311991 :     JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, str);
     659                 : 
     660                 :     /*
     661                 :      * As string can only refer to other strings we fully scan its GC graph
     662                 :      * using the explicit stack when navigating the rope tree to avoid
     663                 :      * dealing with strings on the stack in drainMarkStack.
     664                 :      */
     665       221311991 :     if (str->markIfUnmarked())
     666       194150513 :         ScanString(gcmarker, str);
     667       221311991 : }
     668                 : 
     669                 : void
     670         2872168 : MarkChildren(JSTracer *trc, JSObject *obj)
     671                 : {
     672         2872168 :     obj->markChildren(trc);
     673         2872168 : }
     674                 : 
     675                 : static void
     676        17387228 : MarkChildren(JSTracer *trc, JSString *str)
     677                 : {
     678        17387228 :     if (str->isDependent())
     679            1000 :         str->asDependent().markChildren(trc);
     680        17386228 :     else if (str->isRope())
     681            2172 :         str->asRope().markChildren(trc);
     682        17387228 : }
     683                 : 
     684                 : static void
     685          152539 : MarkChildren(JSTracer *trc, JSScript *script)
     686                 : {
     687          152539 :     script->markChildren(trc);
     688          152539 : }
     689                 : 
     690                 : static void
     691         3670845 : MarkChildren(JSTracer *trc, Shape *shape)
     692                 : {
     693         3670845 :     shape->markChildren(trc);
     694         3670845 : }
     695                 : 
     696                 : static void
     697         1126427 : MarkChildren(JSTracer *trc, BaseShape *base)
     698                 : {
     699         1126427 :     base->markChildren(trc);
     700         1126427 : }
     701                 : 
     702                 : /*
     703                 :  * This function is used by the cycle collector to trace through the
     704                 :  * children of a BaseShape (and its baseUnowned(), if any). The cycle
     705                 :  * collector does not directly care about BaseShapes, so only the
     706                 :  * getter, setter, and parent are marked. Furthermore, the parent is
     707                 :  * marked only if it isn't the same as prevParent, which will be
     708                 :  * updated to the current shape's parent.
     709                 :  */
     710                 : inline void
     711               0 : MarkCycleCollectorChildren(JSTracer *trc, BaseShape *base, JSObject **prevParent)
     712                 : {
     713               0 :     JS_ASSERT(base);
     714                 : 
     715                 :     /*
     716                 :      * The cycle collector does not need to trace unowned base shapes,
     717                 :      * as they have the same getter, setter and parent as the original
     718                 :      * base shape.
     719                 :      */
     720               0 :     base->assertConsistency();
     721                 : 
     722               0 :     if (base->hasGetterObject()) {
     723               0 :         JSObject *tmp = base->getterObject();
     724               0 :         MarkObjectUnbarriered(trc, &tmp, "getter");
     725               0 :         JS_ASSERT(tmp == base->getterObject());
     726                 :     }
     727                 : 
     728               0 :     if (base->hasSetterObject()) {
     729               0 :         JSObject *tmp = base->setterObject();
     730               0 :         MarkObjectUnbarriered(trc, &tmp, "setter");
     731               0 :         JS_ASSERT(tmp == base->setterObject());
     732                 :     }
     733                 : 
     734               0 :     JSObject *parent = base->getObjectParent();
     735               0 :     if (parent && parent != *prevParent) {
     736               0 :         MarkObjectUnbarriered(trc, &parent, "parent");
     737               0 :         JS_ASSERT(parent == base->getObjectParent());
     738               0 :         *prevParent = parent;
     739                 :     }
     740               0 : }
     741                 : 
     742                 : /*
     743                 :  * This function is used by the cycle collector to trace through a
     744                 :  * shape. The cycle collector does not care about shapes or base
     745                 :  * shapes, so those are not marked. Instead, any shapes or base shapes
     746                 :  * that are encountered have their children marked. Stack space is
     747                 :  * bounded. If two shapes in a row have the same parent pointer, the
     748                 :  * parent pointer will only be marked once.
     749                 :  */
     750                 : void
     751               0 : MarkCycleCollectorChildren(JSTracer *trc, Shape *shape)
     752                 : {
     753               0 :     JSObject *prevParent = NULL;
     754               0 :     do {
     755               0 :         MarkCycleCollectorChildren(trc, shape->base(), &prevParent);
     756               0 :         MarkId(trc, &shape->propidRef(), "propid");
     757               0 :         shape = shape->previous();
     758                 :     } while (shape);
     759               0 : }
     760                 : 
     761                 : static void
     762          422238 : ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
     763                 : {
     764          422238 :     if (!type->singleton) {
     765          312574 :         unsigned count = type->getPropertyCount();
     766          324241 :         for (unsigned i = 0; i < count; i++) {
     767           11667 :             types::Property *prop = type->getProperty(i);
     768           11667 :             if (prop && JSID_IS_STRING(prop->id))
     769            8974 :                 PushMarkStack(gcmarker, JSID_TO_STRING(prop->id));
     770                 :         }
     771                 :     }
     772                 : 
     773          422238 :     if (type->proto)
     774          377354 :         PushMarkStack(gcmarker, type->proto);
     775                 : 
     776          422238 :     if (type->singleton && !type->lazy())
     777           64814 :         PushMarkStack(gcmarker, type->singleton);
     778                 : 
     779          422238 :     if (type->newScript) {
     780               5 :         PushMarkStack(gcmarker, type->newScript->fun);
     781               5 :         PushMarkStack(gcmarker, type->newScript->shape);
     782                 :     }
     783                 : 
     784          422238 :     if (type->interpretedFunction)
     785           37268 :         PushMarkStack(gcmarker, type->interpretedFunction);
     786          422238 : }
     787                 : 
     788                 : static void
     789           93503 : MarkChildren(JSTracer *trc, types::TypeObject *type)
     790                 : {
     791           93503 :     if (!type->singleton) {
     792           83015 :         unsigned count = type->getPropertyCount();
     793           84942 :         for (unsigned i = 0; i < count; i++) {
     794            1927 :             types::Property *prop = type->getProperty(i);
     795            1927 :             if (prop)
     796            1927 :                 MarkId(trc, &prop->id, "type_prop");
     797                 :         }
     798                 :     }
     799                 : 
     800           93503 :     if (type->proto)
     801           83303 :         MarkObject(trc, &type->proto, "type_proto");
     802                 : 
     803           93503 :     if (type->singleton && !type->lazy())
     804            6744 :         MarkObject(trc, &type->singleton, "type_singleton");
     805                 : 
     806           93503 :     if (type->newScript) {
     807             100 :         MarkObject(trc, &type->newScript->fun, "type_new_function");
     808             100 :         MarkShape(trc, &type->newScript->shape, "type_new_shape");
     809                 :     }
     810                 : 
     811           93503 :     if (type->interpretedFunction)
     812            9998 :         MarkObject(trc, &type->interpretedFunction, "type_function");
     813           93503 : }
     814                 : 
     815                 : #ifdef JS_HAS_XML_SUPPORT
     816                 : static void
     817             194 : MarkChildren(JSTracer *trc, JSXML *xml)
     818                 : {
     819             194 :     js_TraceXML(trc, xml);
     820             194 : }
     821                 : #endif
     822                 : 
     823                 : template<typename T>
     824                 : void
     825               9 : PushArenaTyped(GCMarker *gcmarker, ArenaHeader *aheader)
     826                 : {
     827              18 :     for (CellIterUnderGC i(aheader); !i.done(); i.next())
     828               9 :         PushMarkStack(gcmarker, i.get<T>());
     829               9 : }
     830                 : 
     831                 : void
     832               9 : PushArena(GCMarker *gcmarker, ArenaHeader *aheader)
     833                 : {
     834               9 :     switch (MapAllocToTraceKind(aheader->getAllocKind())) {
     835                 :       case JSTRACE_OBJECT:
     836               0 :         PushArenaTyped<JSObject>(gcmarker, aheader);
     837               0 :         break;
     838                 : 
     839                 :       case JSTRACE_STRING:
     840               9 :         PushArenaTyped<JSString>(gcmarker, aheader);
     841               9 :         break;
     842                 : 
     843                 :       case JSTRACE_SCRIPT:
     844               0 :         PushArenaTyped<JSScript>(gcmarker, aheader);
     845               0 :         break;
     846                 : 
     847                 :       case JSTRACE_SHAPE:
     848               0 :         PushArenaTyped<js::Shape>(gcmarker, aheader);
     849               0 :         break;
     850                 : 
     851                 :       case JSTRACE_BASE_SHAPE:
     852               0 :         PushArenaTyped<js::BaseShape>(gcmarker, aheader);
     853               0 :         break;
     854                 : 
     855                 :       case JSTRACE_TYPE_OBJECT:
     856               0 :         PushArenaTyped<js::types::TypeObject>(gcmarker, aheader);
     857               0 :         break;
     858                 : 
     859                 : #if JS_HAS_XML_SUPPORT
     860                 :       case JSTRACE_XML:
     861               0 :         PushArenaTyped<JSXML>(gcmarker, aheader);
     862               0 :         break;
     863                 : #endif
     864                 :     }
     865               9 : }
     866                 : 
     867                 : } /* namespace gc */
     868                 : 
     869                 : using namespace js::gc;
     870                 : 
     871                 : struct SlotArrayLayout
     872                 : {
     873                 :     union {
     874                 :         HeapSlot *end;
     875                 :         js::Class *clasp;
     876                 :     };
     877                 :     union {
     878                 :         HeapSlot *start;
     879                 :         uintptr_t index;
     880                 :     };
     881                 :     JSObject *obj;
     882                 : 
     883                 :     static void staticAsserts() {
     884                 :         /* This should have the same layout as three mark stack items. */
     885                 :         JS_STATIC_ASSERT(sizeof(SlotArrayLayout) == 3 * sizeof(uintptr_t));
     886                 :     }
     887                 : };
     888                 : 
     889                 : /*
     890                 :  * During incremental GC, we return from drainMarkStack without having processed
     891                 :  * the entire stack. At that point, JS code can run and reallocate slot arrays
     892                 :  * that are stored on the stack. To prevent this from happening, we replace all
     893                 :  * ValueArrayTag stack items with SavedValueArrayTag. In the latter, slots
     894                 :  * pointers are replaced with slot indexes.
     895                 :  *
     896                 :  * We also replace the slot array end pointer (which can be derived from the obj
     897                 :  * pointer) with the object's class. During JS executation, array slowification
     898                 :  * can cause the layout of slots to change. We can observe that slowification
     899                 :  * happened if the class changed; in that case, we completely rescan the array.
     900                 :  */
     901                 : void
     902              54 : GCMarker::saveValueRanges()
     903                 : {
     904             381 :     for (uintptr_t *p = stack.tos; p > stack.stack; ) {
     905             273 :         uintptr_t tag = *--p & StackTagMask;
     906             273 :         if (tag == ValueArrayTag) {
     907              36 :             p -= 2;
     908              36 :             SlotArrayLayout *arr = reinterpret_cast<SlotArrayLayout *>(p);
     909              36 :             JSObject *obj = arr->obj;
     910                 : 
     911              36 :             if (obj->getClass() == &ArrayClass) {
     912               0 :                 HeapSlot *vp = obj->getDenseArrayElements();
     913               0 :                 JS_ASSERT(arr->start >= vp &&
     914               0 :                           arr->end == vp + obj->getDenseArrayInitializedLength());
     915               0 :                 arr->index = arr->start - vp;
     916                 :             } else {
     917              36 :                 HeapSlot *vp = obj->fixedSlots();
     918              36 :                 unsigned nfixed = obj->numFixedSlots();
     919              36 :                 if (arr->start >= vp && arr->start < vp + nfixed) {
     920              18 :                     JS_ASSERT(arr->end == vp + Min(nfixed, obj->slotSpan()));
     921              18 :                     arr->index = arr->start - vp;
     922                 :                 } else {
     923              18 :                     JS_ASSERT(arr->start >= obj->slots &&
     924              36 :                               arr->end == obj->slots + obj->slotSpan() - nfixed);
     925              18 :                     arr->index = (arr->start - obj->slots) + nfixed;
     926                 :                 }
     927                 :             }
     928              36 :             arr->clasp = obj->getClass();
     929              36 :             p[2] |= SavedValueArrayTag;
     930             237 :         } else if (tag == SavedValueArrayTag) {
     931               0 :             p -= 2;
     932                 :         }
     933                 :     }
     934              54 : }
     935                 : 
     936                 : bool
     937               0 : GCMarker::restoreValueArray(JSObject *obj, void **vpp, void **endp)
     938                 : {
     939               0 :     uintptr_t start = stack.pop();
     940               0 :     js::Class *clasp = reinterpret_cast<js::Class *>(stack.pop());
     941                 : 
     942               0 :     JS_ASSERT(obj->getClass() == clasp ||
     943               0 :               (clasp == &ArrayClass && obj->getClass() == &SlowArrayClass));
     944                 : 
     945               0 :     if (clasp == &ArrayClass) {
     946               0 :         if (obj->getClass() != &ArrayClass)
     947               0 :             return false;
     948                 : 
     949               0 :         uint32_t initlen = obj->getDenseArrayInitializedLength();
     950               0 :         HeapSlot *vp = obj->getDenseArrayElements();
     951               0 :         if (start < initlen) {
     952               0 :             *vpp = vp + start;
     953               0 :             *endp = vp + initlen;
     954                 :         } else {
     955                 :             /* The object shrunk, in which case no scanning is needed. */
     956               0 :             *vpp = *endp = vp;
     957                 :         }
     958                 :     } else {
     959               0 :         HeapSlot *vp = obj->fixedSlots();
     960               0 :         unsigned nfixed = obj->numFixedSlots();
     961               0 :         unsigned nslots = obj->slotSpan();
     962               0 :         if (start < nfixed) {
     963               0 :             *vpp = vp + start;
     964               0 :             *endp = vp + Min(nfixed, nslots);
     965               0 :         } else if (start < nslots) {
     966               0 :             *vpp = obj->slots + start - nfixed;
     967               0 :             *endp = obj->slots + nslots - nfixed;
     968                 :         } else {
     969                 :             /* The object shrunk, in which case no scanning is needed. */
     970               0 :             *vpp = *endp = obj->slots;
     971                 :         }
     972                 :     }
     973                 : 
     974               0 :     JS_ASSERT(*vpp <= *endp);
     975               0 :     return true;
     976                 : }
     977                 : 
     978                 : inline void
     979        15589580 : GCMarker::processMarkStackTop(SliceBudget &budget)
     980                 : {
     981                 :     /*
     982                 :      * The function uses explicit goto and implements the scanning of the
     983                 :      * object directly. It allows to eliminate the tail recursion and
     984                 :      * significantly improve the marking performance, see bug 641025.
     985                 :      */
     986                 :     HeapSlot *vp, *end;
     987                 :     JSObject *obj;
     988                 : 
     989        15589580 :     uintptr_t addr = stack.pop();
     990        15589580 :     uintptr_t tag = addr & StackTagMask;
     991        15589580 :     addr &= ~StackTagMask;
     992                 : 
     993        15589580 :     if (tag == ValueArrayTag) {
     994                 :         JS_STATIC_ASSERT(ValueArrayTag == 0);
     995        11472011 :         JS_ASSERT(!(addr & Cell::CellMask));
     996        11472011 :         obj = reinterpret_cast<JSObject *>(addr);
     997        11472011 :         uintptr_t addr2 = stack.pop();
     998        11472011 :         uintptr_t addr3 = stack.pop();
     999        11472011 :         JS_ASSERT(addr2 <= addr3);
    1000        11472011 :         JS_ASSERT((addr3 - addr2) % sizeof(Value) == 0);
    1001        11472011 :         vp = reinterpret_cast<HeapSlot *>(addr2);
    1002        11472011 :         end = reinterpret_cast<HeapSlot *>(addr3);
    1003        11472011 :         goto scan_value_array;
    1004                 :     }
    1005                 : 
    1006         4117569 :     if (tag == ObjectTag) {
    1007         3695137 :         obj = reinterpret_cast<JSObject *>(addr);
    1008         3695137 :         JS_COMPARTMENT_ASSERT(runtime, obj);
    1009         3695137 :         goto scan_obj;
    1010                 :     }
    1011                 : 
    1012          422432 :     if (tag == TypeTag) {
    1013          422238 :         ScanTypeObject(this, reinterpret_cast<types::TypeObject *>(addr));
    1014             194 :     } else if (tag == SavedValueArrayTag) {
    1015               0 :         JS_ASSERT(!(addr & Cell::CellMask));
    1016               0 :         obj = reinterpret_cast<JSObject *>(addr);
    1017               0 :         if (restoreValueArray(obj, (void **)&vp, (void **)&end))
    1018               0 :             goto scan_value_array;
    1019                 :         else
    1020               0 :             goto scan_obj;
    1021                 :     } else {
    1022             194 :         JS_ASSERT(tag == XmlTag);
    1023             194 :         MarkChildren(this, reinterpret_cast<JSXML *>(addr));
    1024                 :     }
    1025          422432 :     budget.step();
    1026          422432 :     return;
    1027                 : 
    1028                 :   scan_value_array:
    1029        27947880 :     JS_ASSERT(vp <= end);
    1030        95680042 :     while (vp != end) {
    1031        52576017 :         budget.step();
    1032        52576017 :         if (budget.isOverBudget()) {
    1033              18 :             pushValueArray(obj, vp, end);
    1034              18 :             return;
    1035                 :         }
    1036                 : 
    1037        52575999 :         const Value &v = *vp++;
    1038        52575999 :         if (v.isString()) {
    1039        12782586 :             JSString *str = v.toString();
    1040        12782586 :             JS_COMPARTMENT_ASSERT_STR(runtime, str);
    1041        12782586 :             if (str->markIfUnmarked())
    1042         4983352 :                 ScanString(this, str);
    1043        39793413 :         } else if (v.isObject()) {
    1044        19760943 :             JSObject *obj2 = &v.toObject();
    1045        19760943 :             JS_COMPARTMENT_ASSERT(runtime, obj2);
    1046        19760943 :             if (obj2->markIfUnmarked(getMarkColor())) {
    1047        12791717 :                 pushValueArray(obj, vp, end);
    1048        12791717 :                 obj = obj2;
    1049        12791717 :                 goto scan_obj;
    1050                 :             }
    1051                 :         }
    1052                 :     }
    1053        15156145 :     return;
    1054                 : 
    1055                 :   scan_obj:
    1056                 :     {
    1057        16486854 :         JS_COMPARTMENT_ASSERT(runtime, obj);
    1058                 : 
    1059        16486854 :         budget.step();
    1060        16486854 :         if (budget.isOverBudget()) {
    1061              27 :             pushObject(obj);
    1062              27 :             return;
    1063                 :         }
    1064                 : 
    1065        16486827 :         types::TypeObject *type = obj->typeFromGC();
    1066        16486827 :         PushMarkStack(this, type);
    1067                 : 
    1068        16486827 :         Shape *shape = obj->lastProperty();
    1069        16486827 :         PushMarkStack(this, shape);
    1070                 : 
    1071                 :         /* Call the trace hook if necessary. */
    1072        16486827 :         Class *clasp = shape->getObjectClass();
    1073        16486827 :         if (clasp->trace) {
    1074        14239843 :             if (clasp == &ArrayClass) {
    1075          625429 :                 JS_ASSERT(!shape->isNative());
    1076          625429 :                 vp = obj->getDenseArrayElements();
    1077          625429 :                 end = vp + obj->getDenseArrayInitializedLength();
    1078          625429 :                 goto scan_value_array;
    1079                 :             } else {
    1080               0 :                 JS_ASSERT_IF(runtime->gcIncrementalState != NO_INCREMENTAL,
    1081        13614414 :                              clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
    1082                 :             }
    1083        13614414 :             clasp->trace(this, obj);
    1084                 :         }
    1085                 : 
    1086        15861398 :         if (!shape->isNative())
    1087           10958 :             return;
    1088                 : 
    1089        15850440 :         unsigned nslots = obj->slotSpan();
    1090        15850440 :         vp = obj->fixedSlots();
    1091        15850440 :         if (obj->slots) {
    1092         5812532 :             unsigned nfixed = obj->numFixedSlots();
    1093         5812532 :             if (nslots > nfixed) {
    1094         5812532 :                 pushValueArray(obj, vp, vp + nfixed);
    1095         5812532 :                 vp = obj->slots;
    1096         5812532 :                 end = vp + (nslots - nfixed);
    1097         5812532 :                 goto scan_value_array;
    1098                 :             }
    1099                 :         }
    1100        10037908 :         JS_ASSERT(nslots <= obj->numFixedSlots());
    1101        10037908 :         end = vp + nslots;
    1102        10037908 :         goto scan_value_array;
    1103                 :     }
    1104                 : }
    1105                 : 
    1106                 : bool
    1107           77246 : GCMarker::drainMarkStack(SliceBudget &budget)
    1108                 : {
    1109                 : #ifdef DEBUG
    1110           77246 :     JSRuntime *rt = runtime;
    1111                 : 
    1112                 :     struct AutoCheckCompartment {
    1113                 :         JSRuntime *runtime;
    1114           77246 :         AutoCheckCompartment(JSRuntime *rt) : runtime(rt) {
    1115           77246 :             JS_ASSERT(!rt->gcStrictCompartmentChecking);
    1116           77246 :             runtime->gcStrictCompartmentChecking = true;
    1117           77246 :         }
    1118           77246 :         ~AutoCheckCompartment() { runtime->gcStrictCompartmentChecking = false; }
    1119          154492 :     } acc(rt);
    1120                 : #endif
    1121                 : 
    1122           77246 :     if (budget.isOverBudget())
    1123               0 :         return false;
    1124                 : 
    1125               9 :     for (;;) {
    1126        15744036 :         while (!stack.isEmpty()) {
    1127        15589580 :             processMarkStackTop(budget);
    1128        15589580 :             if (budget.isOverBudget()) {
    1129              54 :                 saveValueRanges();
    1130              54 :                 return false;
    1131                 :             }
    1132                 :         }
    1133                 : 
    1134           77201 :         if (!hasDelayedChildren())
    1135                 :             break;
    1136                 : 
    1137                 :         /*
    1138                 :          * Mark children of things that caused too deep recursion during the
    1139                 :          * above tracing. Don't do this until we're done with everything
    1140                 :          * else.
    1141                 :          */
    1142               9 :         if (!markDelayedChildren(budget)) {
    1143               0 :             saveValueRanges();
    1144               0 :             return false;
    1145                 :         }
    1146                 :     }
    1147                 : 
    1148           77192 :     return true;
    1149                 : }
    1150                 : 
    1151                 : void
    1152        25175500 : TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind)
    1153                 : {
    1154        25175500 :     switch (kind) {
    1155                 :       case JSTRACE_OBJECT:
    1156         2872168 :         MarkChildren(trc, static_cast<JSObject *>(thing));
    1157         2872168 :         break;
    1158                 : 
    1159                 :       case JSTRACE_STRING:
    1160        17387228 :         MarkChildren(trc, static_cast<JSString *>(thing));
    1161        17387228 :         break;
    1162                 : 
    1163                 :       case JSTRACE_SCRIPT:
    1164           25329 :         MarkChildren(trc, static_cast<JSScript *>(thing));
    1165           25329 :         break;
    1166                 : 
    1167                 :       case JSTRACE_SHAPE:
    1168         3670845 :         MarkChildren(trc, static_cast<Shape *>(thing));
    1169         3670845 :         break;
    1170                 : 
    1171                 :       case JSTRACE_BASE_SHAPE:
    1172         1126427 :         MarkChildren(trc, static_cast<BaseShape *>(thing));
    1173         1126427 :         break;
    1174                 : 
    1175                 :       case JSTRACE_TYPE_OBJECT:
    1176           93503 :         MarkChildren(trc, (types::TypeObject *)thing);
    1177           93503 :         break;
    1178                 : 
    1179                 : #if JS_HAS_XML_SUPPORT
    1180                 :       case JSTRACE_XML:
    1181               0 :         MarkChildren(trc, static_cast<JSXML *>(thing));
    1182               0 :         break;
    1183                 : #endif
    1184                 :     }
    1185        25175500 : }
    1186                 : 
    1187                 : void
    1188               0 : CallTracer(JSTracer *trc, void *thing, JSGCTraceKind kind)
    1189                 : {
    1190               0 :     JS_ASSERT(thing);
    1191               0 :     void *tmp = thing;
    1192               0 :     MarkKind(trc, &tmp, kind);
    1193               0 :     JS_ASSERT(tmp == thing);
    1194               0 : }
    1195                 : 
    1196                 : } /* namespace js */

Generated by: LCOV version 1.7