LCOV - app.info - js/src/jsgcmark.cpp

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