LCOV - code coverage report
Current view: directory - js/src - jsgcinlines.h (source / functions) Found Hit Coverage
Test: app.info Lines: 188 172 91.5 %
Date: 2012-06-02 Functions: 50 43 86.0 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  *
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is SpiderMonkey code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Mozilla Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #ifndef jsgcinlines_h___
      41                 : #define jsgcinlines_h___
      42                 : 
      43                 : #include "jsgc.h"
      44                 : #include "jscntxt.h"
      45                 : #include "jscompartment.h"
      46                 : #include "jslock.h"
      47                 : #include "jsscope.h"
      48                 : #include "jsxml.h"
      49                 : 
      50                 : #include "js/TemplateLib.h"
      51                 : 
      52                 : namespace js {
      53                 : 
      54                 : struct Shape;
      55                 : 
      56                 : namespace gc {
      57                 : 
      58                 : inline JSGCTraceKind
      59        89948620 : GetGCThingTraceKind(const void *thing)
      60                 : {
      61        89948620 :     JS_ASSERT(thing);
      62        89948620 :     const Cell *cell = reinterpret_cast<const Cell *>(thing);
      63        89948620 :     return MapAllocToTraceKind(cell->getAllocKind());
      64                 : }
      65                 : 
      66                 : /* Capacity for slotsToThingKind */
      67                 : const size_t SLOTS_TO_THING_KIND_LIMIT = 17;
      68                 : 
      69                 : /* Get the best kind to use when making an object with the given slot count. */
      70                 : static inline AllocKind
      71        22938476 : GetGCObjectKind(size_t numSlots)
      72                 : {
      73                 :     extern AllocKind slotsToThingKind[];
      74                 : 
      75        22938476 :     if (numSlots >= SLOTS_TO_THING_KIND_LIMIT)
      76          289842 :         return FINALIZE_OBJECT16;
      77        22648634 :     return slotsToThingKind[numSlots];
      78                 : }
      79                 : 
      80                 : static inline AllocKind
      81        15443903 : GetGCObjectKind(Class *clasp)
      82                 : {
      83        15443903 :     if (clasp == &FunctionClass)
      84          115911 :         return JSFunction::FinalizeKind;
      85        15327992 :     uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp);
      86        15327992 :     if (clasp->flags & JSCLASS_HAS_PRIVATE)
      87         2489547 :         nslots++;
      88        15327992 :     return GetGCObjectKind(nslots);
      89                 : }
      90                 : 
      91                 : /* As for GetGCObjectKind, but for dense array allocation. */
      92                 : static inline AllocKind
      93         2558224 : GetGCArrayKind(size_t numSlots)
      94                 : {
      95                 :     extern AllocKind slotsToThingKind[];
      96                 : 
      97                 :     /*
      98                 :      * Dense arrays can use their fixed slots to hold their elements array
      99                 :      * (less two Values worth of ObjectElements header), but if more than the
     100                 :      * maximum number of fixed slots is needed then the fixed slots will be
     101                 :      * unused.
     102                 :      */
     103                 :     JS_STATIC_ASSERT(ObjectElements::VALUES_PER_HEADER == 2);
     104         2558224 :     if (numSlots > JSObject::NELEMENTS_LIMIT || numSlots + 2 >= SLOTS_TO_THING_KIND_LIMIT)
     105          103352 :         return FINALIZE_OBJECT2;
     106         2454872 :     return slotsToThingKind[numSlots + 2];
     107                 : }
     108                 : 
     109                 : static inline AllocKind
     110         2613913 : GetGCObjectFixedSlotsKind(size_t numFixedSlots)
     111                 : {
     112                 :     extern AllocKind slotsToThingKind[];
     113                 : 
     114         2613913 :     JS_ASSERT(numFixedSlots < SLOTS_TO_THING_KIND_LIMIT);
     115         2613913 :     return slotsToThingKind[numFixedSlots];
     116                 : }
     117                 : 
     118                 : static inline bool
     119        53376477 : IsBackgroundAllocKind(AllocKind kind)
     120                 : {
     121        53376477 :     JS_ASSERT(kind <= FINALIZE_LAST);
     122        53376477 :     return kind <= FINALIZE_OBJECT_LAST && kind % 2 == 1;
     123                 : }
     124                 : 
     125                 : static inline AllocKind
     126        15552536 : GetBackgroundAllocKind(AllocKind kind)
     127                 : {
     128        15552536 :     JS_ASSERT(!IsBackgroundAllocKind(kind));
     129        15552536 :     return (AllocKind) (kind + 1);
     130                 : }
     131                 : 
     132                 : /*
     133                 :  * Try to get the next larger size for an object, keeping BACKGROUND
     134                 :  * consistent.
     135                 :  */
     136                 : static inline bool
     137              17 : TryIncrementAllocKind(AllocKind *kindp)
     138                 : {
     139              17 :     size_t next = size_t(*kindp) + 2;
     140              17 :     if (next >= size_t(FINALIZE_OBJECT_LIMIT))
     141               0 :         return false;
     142              17 :     *kindp = AllocKind(next);
     143              17 :     return true;
     144                 : }
     145                 : 
     146                 : /* Get the number of fixed slots and initial capacity associated with a kind. */
     147                 : static inline size_t
     148        38120267 : GetGCKindSlots(AllocKind thingKind)
     149                 : {
     150                 :     /* Using a switch in hopes that thingKind will usually be a compile-time constant. */
     151        38120267 :     switch (thingKind) {
     152                 :       case FINALIZE_OBJECT0:
     153                 :       case FINALIZE_OBJECT0_BACKGROUND:
     154         1949371 :         return 0;
     155                 :       case FINALIZE_OBJECT2:
     156                 :       case FINALIZE_OBJECT2_BACKGROUND:
     157        19279947 :         return 2;
     158                 :       case FINALIZE_OBJECT4:
     159                 :       case FINALIZE_OBJECT4_BACKGROUND:
     160        11538849 :         return 4;
     161                 :       case FINALIZE_OBJECT8:
     162                 :       case FINALIZE_OBJECT8_BACKGROUND:
     163         2649692 :         return 8;
     164                 :       case FINALIZE_OBJECT12:
     165                 :       case FINALIZE_OBJECT12_BACKGROUND:
     166         1991414 :         return 12;
     167                 :       case FINALIZE_OBJECT16:
     168                 :       case FINALIZE_OBJECT16_BACKGROUND:
     169          710994 :         return 16;
     170                 :       default:
     171               0 :         JS_NOT_REACHED("Bad object finalize kind");
     172                 :         return 0;
     173                 :     }
     174                 : }
     175                 : 
     176                 : static inline size_t
     177        28708598 : GetGCKindSlots(AllocKind thingKind, Class *clasp)
     178                 : {
     179        28708598 :     size_t nslots = GetGCKindSlots(thingKind);
     180                 : 
     181                 :     /* An object's private data uses the space taken by its last fixed slot. */
     182        28708598 :     if (clasp->flags & JSCLASS_HAS_PRIVATE) {
     183         7918939 :         JS_ASSERT(nslots > 0);
     184         7918939 :         nslots--;
     185                 :     }
     186                 : 
     187                 :     /*
     188                 :      * Functions have a larger finalize kind than FINALIZE_OBJECT to reserve
     189                 :      * space for the extra fields in JSFunction, but have no fixed slots.
     190                 :      */
     191        28708598 :     if (clasp == &FunctionClass)
     192        16039372 :         nslots = 0;
     193                 : 
     194        28708598 :     return nslots;
     195                 : }
     196                 : 
     197                 : static inline void
     198           21124 : GCPoke(JSRuntime *rt, Value oldval)
     199                 : {
     200                 :     /*
     201                 :      * Since we're forcing a GC from JS_GC anyway, don't bother wasting cycles
     202                 :      * loading oldval.  XXX remove implied force, fix jsinterp.c's "second arg
     203                 :      * ignored", etc.
     204                 :      */
     205                 : #if 1
     206           21124 :     rt->gcPoke = true;
     207                 : #else
     208                 :     rt->gcPoke = oldval.isGCThing();
     209                 : #endif
     210                 : 
     211                 : #ifdef JS_GC_ZEAL
     212                 :     /* Schedule a GC to happen "soon" after a GC poke. */
     213           21124 :     if (rt->gcZeal() == js::gc::ZealPokeValue)
     214               0 :         rt->gcNextScheduled = 1;
     215                 : #endif
     216           21124 : }
     217                 : 
     218                 : /*
     219                 :  * Invoke ArenaOp and CellOp on every arena and cell in a compartment which
     220                 :  * have the specified thing kind.
     221                 :  */
     222                 : template <class ArenaOp, class CellOp>
     223                 : void
     224          122622 : ForEachArenaAndCell(JSCompartment *compartment, AllocKind thingKind,
     225                 :                     ArenaOp arenaOp, CellOp cellOp)
     226                 : {
     227          122622 :     size_t thingSize = Arena::thingSize(thingKind);
     228          122622 :     ArenaHeader *aheader = compartment->arenas.getFirstArena(thingKind);
     229                 : 
     230          204583 :     for (; aheader; aheader = aheader->next) {
     231           81961 :         Arena *arena = aheader->getArena();
     232           81961 :         arenaOp(arena);
     233           81961 :         FreeSpan firstSpan(aheader->getFirstFreeSpan());
     234           81961 :         const FreeSpan *span = &firstSpan;
     235                 : 
     236         3159017 :         for (uintptr_t thing = arena->thingsStart(thingKind); ; thing += thingSize) {
     237         3159017 :             JS_ASSERT(thing <= arena->thingsEnd());
     238         3159017 :             if (thing == span->first) {
     239          245337 :                 if (!span->hasNext())
     240                 :                     break;
     241          163376 :                 thing = span->last;
     242          163376 :                 span = span->nextSpan();
     243                 :             } else {
     244         2913680 :                 Cell *t = reinterpret_cast<Cell *>(thing);
     245         2913680 :                 cellOp(t);
     246                 :             }
     247                 :         }
     248                 :     }
     249          122622 : }
     250                 : 
     251                 : class CellIterImpl
     252                 : {
     253                 :     size_t firstThingOffset;
     254                 :     size_t thingSize;
     255                 :     ArenaHeader *aheader;
     256                 :     FreeSpan firstSpan;
     257                 :     const FreeSpan *span;
     258                 :     uintptr_t thing;
     259                 :     Cell *cell;
     260                 : 
     261                 :   protected:
     262          358274 :     CellIterImpl() {
     263          358274 :     }
     264                 : 
     265          358274 :     void initSpan(JSCompartment *comp, AllocKind kind) {
     266          358274 :         JS_ASSERT(comp->arenas.isSynchronizedFreeList(kind));
     267          358274 :         firstThingOffset = Arena::firstThingOffset(kind);
     268          358274 :         thingSize = Arena::thingSize(kind);
     269          358274 :         firstSpan.initAsEmpty();
     270          358274 :         span = &firstSpan;
     271          358274 :         thing = span->first;
     272          358274 :     }
     273                 : 
     274               0 :     void init(ArenaHeader *singleAheader) {
     275               0 :         aheader = singleAheader;
     276               0 :         initSpan(aheader->compartment, aheader->getAllocKind());
     277               0 :         next();
     278               0 :         aheader = NULL;
     279               0 :     }
     280                 : 
     281          358274 :     void init(JSCompartment *comp, AllocKind kind) {
     282          358274 :         initSpan(comp, kind);
     283          358274 :         aheader = comp->arenas.getFirstArena(kind);
     284          358274 :         next();
     285          358274 :     }
     286                 : 
     287                 :   public:
     288        58456381 :     bool done() const {
     289        58456381 :         return !cell;
     290                 :     }
     291                 : 
     292        29055088 :     template<typename T> T *get() const {
     293        29055088 :         JS_ASSERT(!done());
     294        29055088 :         return static_cast<T *>(cell);
     295                 :     }
     296                 : 
     297               0 :     Cell *getCell() const {
     298               0 :         JS_ASSERT(!done());
     299               0 :         return cell;
     300                 :     }
     301                 : 
     302        30792631 :     void next() {
     303         1391338 :         for (;;) {
     304        30792631 :             if (thing != span->first)
     305        28454491 :                 break;
     306         2338140 :             if (JS_LIKELY(span->hasNext())) {
     307          588528 :                 thing = span->last + thingSize;
     308          588528 :                 span = span->nextSpan();
     309          588528 :                 break;
     310                 :             }
     311         1749612 :             if (!aheader) {
     312          358274 :                 cell = NULL;
     313          358274 :                 return;
     314                 :             }
     315         1391338 :             firstSpan = aheader->getFirstFreeSpan();
     316         1391338 :             span = &firstSpan;
     317         1391338 :             thing = aheader->arenaAddress() | firstThingOffset;
     318         1391338 :             aheader = aheader->next;
     319                 :         }
     320        29043019 :         cell = reinterpret_cast<Cell *>(thing);
     321        29043019 :         thing += thingSize;
     322                 :     }
     323                 : };
     324                 : 
     325                 : class CellIterUnderGC : public CellIterImpl
     326                 : {
     327                 :   public:
     328          291482 :     CellIterUnderGC(JSCompartment *comp, AllocKind kind) {
     329          291482 :         JS_ASSERT(comp->rt->gcRunning);
     330          291482 :         init(comp, kind);
     331          291482 :     }
     332                 : 
     333               0 :     CellIterUnderGC(ArenaHeader *aheader) {
     334               0 :         JS_ASSERT(aheader->compartment->rt->gcRunning);
     335               0 :         init(aheader);
     336               0 :     }
     337                 : };
     338                 : 
     339                 : /*
     340                 :  * When using the iterator outside the GC the caller must ensure that no GC or
     341                 :  * allocations of GC things are possible and that the background finalization
     342                 :  * for the given thing kind is not enabled or is done.
     343                 :  */
     344                 : class CellIter : public CellIterImpl
     345                 : {
     346                 :     ArenaLists *lists;
     347                 :     AllocKind kind;
     348                 : #ifdef DEBUG
     349                 :     size_t *counter;
     350                 : #endif
     351                 :   public:
     352           66792 :     CellIter(JSCompartment *comp, AllocKind kind)
     353                 :       : lists(&comp->arenas),
     354           66792 :         kind(kind)
     355                 :     {
     356                 :         /*
     357                 :          * We have a single-threaded runtime, so there's no need to protect
     358                 :          * against other threads iterating or allocating. However, we do have
     359                 :          * background finalization; make sure people aren't using CellIter to
     360                 :          * walk such allocation kinds.
     361                 :          */
     362           66792 :         JS_ASSERT(!IsBackgroundAllocKind(kind));
     363           66792 :         if (lists->isSynchronizedFreeList(kind)) {
     364           34807 :             lists = NULL;
     365                 :         } else {
     366           31985 :             JS_ASSERT(!comp->rt->gcRunning);
     367           31985 :             lists->copyFreeListToArena(kind);
     368                 :         }
     369                 : #ifdef DEBUG
     370           66792 :         counter = &comp->rt->noGCOrAllocationCheck;
     371           66792 :         ++*counter;
     372                 : #endif
     373           66792 :         init(comp, kind);
     374           66792 :     }
     375                 : 
     376           66792 :     ~CellIter() {
     377                 : #ifdef DEBUG
     378           66792 :         JS_ASSERT(*counter > 0);
     379           66792 :         --*counter;
     380                 : #endif
     381           66792 :         if (lists)
     382           31985 :             lists->clearFreeListInArena(kind);
     383           66792 :     }
     384                 : };
     385                 : 
     386                 : /* Signatures for ArenaOp and CellOp above. */
     387                 : 
     388           80872 : inline void EmptyArenaOp(Arena *arena) {}
     389                 : inline void EmptyCellOp(Cell *t) {}
     390                 : 
     391                 : /*
     392                 :  * Allocates a new GC thing. After a successful allocation the caller must
     393                 :  * fully initialize the thing before calling any function that can potentially
     394                 :  * trigger GC. This will ensure that GC tracing never sees junk values stored
     395                 :  * in the partially initialized thing.
     396                 :  */
     397                 : 
     398                 : template <typename T>
     399                 : inline T *
     400       241631423 : NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
     401                 : {
     402       241631423 :     JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
     403                 : #ifdef JS_THREADSAFE
     404       241631423 :     JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
     405                 :                  kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
     406                 : #endif
     407       241631423 :     JS_ASSERT(!cx->runtime->gcRunning);
     408       241631423 :     JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
     409                 : 
     410                 :     /* For testing out of memory conditions */
     411       241631423 :     JS_OOM_POSSIBLY_FAIL();
     412                 : 
     413                 : #ifdef JS_GC_ZEAL
     414       241631423 :     if (cx->runtime->needZealousGC())
     415            9042 :         js::gc::RunDebugGC(cx);
     416                 : #endif
     417                 : 
     418       241631423 :     js::gc::MaybeCheckStackRoots(cx);
     419                 : 
     420       241631416 :     JSCompartment *comp = cx->compartment;
     421       241631416 :     void *t = comp->arenas.allocateFromFreeList(kind, thingSize);
     422       241631417 :     if (!t)
     423         2339906 :         t = js::gc::ArenaLists::refillFreeList(cx, kind);
     424                 : 
     425       241631417 :     JS_ASSERT_IF(t && comp->needsBarrier(),
     426                 :                  static_cast<T *>(t)->arenaHeader()->allocatedDuringIncremental);
     427       241631417 :     return static_cast<T *>(t);
     428                 : }
     429                 : 
     430                 : /* Alternate form which allocates a GC thing if doing so cannot trigger a GC. */
     431                 : template <typename T>
     432                 : inline T *
     433        28743683 : TryNewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
     434                 : {
     435        28743683 :     JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
     436                 : #ifdef JS_THREADSAFE
     437        28743683 :     JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
     438                 :                  kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
     439                 : #endif
     440        28743683 :     JS_ASSERT(!cx->runtime->gcRunning);
     441        28743683 :     JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
     442                 : 
     443                 : #ifdef JS_GC_ZEAL
     444        28743683 :     if (cx->runtime->needZealousGC())
     445            1506 :         return NULL;
     446                 : #endif
     447                 : 
     448        28742177 :     void *t = cx->compartment->arenas.allocateFromFreeList(kind, thingSize);
     449        28742177 :     JS_ASSERT_IF(t && cx->compartment->needsBarrier(),
     450                 :                  static_cast<T *>(t)->arenaHeader()->allocatedDuringIncremental);
     451        28742177 :     return static_cast<T *>(t);
     452                 : }
     453                 : 
     454                 : } /* namespace gc */
     455                 : } /* namespace js */
     456                 : 
     457                 : inline JSObject *
     458        11857167 : js_NewGCObject(JSContext *cx, js::gc::AllocKind kind)
     459                 : {
     460        11857167 :     JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
     461        11857167 :     return js::gc::NewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
     462                 : }
     463                 : 
     464                 : inline JSObject *
     465        28743683 : js_TryNewGCObject(JSContext *cx, js::gc::AllocKind kind)
     466                 : {
     467        28743683 :     JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
     468        28743683 :     return js::gc::TryNewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
     469                 : }
     470                 : 
     471                 : inline JSString *
     472       129036224 : js_NewGCString(JSContext *cx)
     473                 : {
     474       129036224 :     return js::gc::NewGCThing<JSString>(cx, js::gc::FINALIZE_STRING, sizeof(JSString));
     475                 : }
     476                 : 
     477                 : inline JSShortString *
     478        52757012 : js_NewGCShortString(JSContext *cx)
     479                 : {
     480        52757012 :     return js::gc::NewGCThing<JSShortString>(cx, js::gc::FINALIZE_SHORT_STRING, sizeof(JSShortString));
     481                 : }
     482                 : 
     483                 : inline JSExternalString *
     484          977008 : js_NewGCExternalString(JSContext *cx)
     485                 : {
     486                 :     return js::gc::NewGCThing<JSExternalString>(cx, js::gc::FINALIZE_EXTERNAL_STRING,
     487          977008 :                                                 sizeof(JSExternalString));
     488                 : }
     489                 : 
     490                 : inline JSScript *
     491         1324850 : js_NewGCScript(JSContext *cx)
     492                 : {
     493         1324850 :     return js::gc::NewGCThing<JSScript>(cx, js::gc::FINALIZE_SCRIPT, sizeof(JSScript));
     494                 : }
     495                 : 
     496                 : inline js::Shape *
     497        32712764 : js_NewGCShape(JSContext *cx)
     498                 : {
     499        32712764 :     return js::gc::NewGCThing<js::Shape>(cx, js::gc::FINALIZE_SHAPE, sizeof(js::Shape));
     500                 : }
     501                 : 
     502                 : inline js::BaseShape *
     503         7567456 : js_NewGCBaseShape(JSContext *cx)
     504                 : {
     505         7567456 :     return js::gc::NewGCThing<js::BaseShape>(cx, js::gc::FINALIZE_BASE_SHAPE, sizeof(js::BaseShape));
     506                 : }
     507                 : 
     508                 : #if JS_HAS_XML_SUPPORT
     509                 : extern JSXML *
     510                 : js_NewGCXML(JSContext *cx);
     511                 : #endif
     512                 : 
     513                 : #endif /* jsgcinlines_h___ */

Generated by: LCOV version 1.7