LCOV - code coverage report
Current view: directory - js/src - jscompartment.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 359 326 90.8 %
Date: 2012-06-02 Functions: 32 31 96.9 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=4 sw=4 et tw=99:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
      18                 :  * May 28, 2008.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  *   Mozilla Foundation
      22                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "jscntxt.h"
      42                 : #include "jscompartment.h"
      43                 : #include "jsgc.h"
      44                 : #include "jsgcmark.h"
      45                 : #include "jsiter.h"
      46                 : #include "jsmath.h"
      47                 : #include "jsproxy.h"
      48                 : #include "jsscope.h"
      49                 : #include "jswatchpoint.h"
      50                 : #include "jswrapper.h"
      51                 : 
      52                 : #include "assembler/wtf/Platform.h"
      53                 : #include "js/MemoryMetrics.h"
      54                 : #include "methodjit/MethodJIT.h"
      55                 : #include "methodjit/PolyIC.h"
      56                 : #include "methodjit/MonoIC.h"
      57                 : #include "vm/Debugger.h"
      58                 : #include "yarr/BumpPointerAllocator.h"
      59                 : 
      60                 : #include "jsgcinlines.h"
      61                 : #include "jsobjinlines.h"
      62                 : #include "jsscopeinlines.h"
      63                 : 
      64                 : #if ENABLE_YARR_JIT
      65                 : #include "assembler/jit/ExecutableAllocator.h"
      66                 : #endif
      67                 : 
      68                 : using namespace mozilla;
      69                 : using namespace js;
      70                 : using namespace js::gc;
      71                 : 
      72           45576 : JSCompartment::JSCompartment(JSRuntime *rt)
      73                 :   : rt(rt),
      74                 :     principals(NULL),
      75                 :     needsBarrier_(false),
      76                 :     gcBytes(0),
      77                 :     gcTriggerBytes(0),
      78                 :     hold(false),
      79                 :     typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
      80                 :     data(NULL),
      81                 :     active(false),
      82                 : #ifdef JS_METHODJIT
      83                 :     jaegerCompartment_(NULL),
      84                 : #endif
      85                 :     regExps(rt),
      86                 :     propertyTree(thisForCtor()),
      87                 :     emptyTypeObject(NULL),
      88                 :     gcMallocAndFreeBytes(0),
      89                 :     gcTriggerMallocAndFreeBytes(0),
      90                 :     gcMallocBytes(0),
      91                 :     debugModeBits(rt->debugMode ? DebugFromC : 0),
      92                 :     mathCache(NULL),
      93           45576 :     watchpointMap(NULL)
      94                 : {
      95           45576 :     PodArrayZero(evalCache);
      96           45576 :     setGCMaxMallocBytes(rt->gcMaxMallocBytes * 0.9);
      97           45576 : }
      98                 : 
      99           91142 : JSCompartment::~JSCompartment()
     100                 : {
     101                 : #ifdef JS_METHODJIT
     102           45571 :     Foreground::delete_(jaegerCompartment_);
     103                 : #endif
     104                 : 
     105           45571 :     Foreground::delete_(mathCache);
     106           45571 :     Foreground::delete_(watchpointMap);
     107                 : 
     108                 : #ifdef DEBUG
     109         2962115 :     for (size_t i = 0; i < ArrayLength(evalCache); ++i)
     110         2916544 :         JS_ASSERT(!evalCache[i]);
     111                 : #endif
     112           45571 : }
     113                 : 
     114                 : bool
     115           45576 : JSCompartment::init(JSContext *cx)
     116                 : {
     117           45576 :     activeAnalysis = activeInference = false;
     118           45576 :     types.init(cx);
     119                 : 
     120           45576 :     newObjectCache.reset();
     121                 : 
     122           45576 :     if (!crossCompartmentWrappers.init())
     123               0 :         return false;
     124                 : 
     125           45576 :     if (!regExps.init(cx))
     126               0 :         return false;
     127                 : 
     128           45576 :     if (!scriptFilenameTable.init())
     129               0 :         return false;
     130                 : 
     131           45576 :     return debuggees.init();
     132                 : }
     133                 : 
     134                 : #ifdef JS_METHODJIT
     135                 : bool
     136        16184670 : JSCompartment::ensureJaegerCompartmentExists(JSContext *cx)
     137                 : {
     138        16184670 :     if (jaegerCompartment_)
     139        16172844 :         return true;
     140                 : 
     141           11826 :     mjit::JaegerCompartment *jc = cx->new_<mjit::JaegerCompartment>();
     142           11826 :     if (!jc)
     143               0 :         return false;
     144           11826 :     if (!jc->Initialize(cx)) {
     145               0 :         cx->delete_(jc);
     146               0 :         return false;
     147                 :     }
     148           11826 :     jaegerCompartment_ = jc;
     149           11826 :     return true;
     150                 : }
     151                 : 
     152                 : size_t
     153              18 : JSCompartment::sizeOfMjitCode() const
     154                 : {
     155              18 :     if (!jaegerCompartment_)
     156              12 :         return 0;
     157                 : 
     158                 :     size_t method, regexp, unused;
     159               6 :     jaegerCompartment_->execAlloc()->sizeOfCode(&method, &regexp, &unused);
     160               6 :     JS_ASSERT(regexp == 0);
     161               6 :     return method + unused;
     162                 : }
     163                 : 
     164                 : #endif
     165                 : 
     166                 : bool
     167         2625178 : JSCompartment::wrap(JSContext *cx, Value *vp)
     168                 : {
     169         2625178 :     JS_ASSERT(cx->compartment == this);
     170                 : 
     171         2625178 :     unsigned flags = 0;
     172                 : 
     173         2625178 :     JS_CHECK_RECURSION(cx, return false);
     174                 : 
     175                 :     /* Only GC things have to be wrapped or copied. */
     176         2625170 :     if (!vp->isMarkable())
     177           77386 :         return true;
     178                 : 
     179         2547784 :     if (vp->isString()) {
     180          555980 :         JSString *str = vp->toString();
     181                 : 
     182                 :         /* If the string is already in this compartment, we are done. */
     183          555980 :         if (str->compartment() == this)
     184             460 :             return true;
     185                 : 
     186                 :         /* If the string is an atom, we don't have to copy. */
     187          555520 :         if (str->isAtom()) {
     188          541315 :             JS_ASSERT(str->compartment() == cx->runtime->atomsCompartment);
     189          541315 :             return true;
     190                 :         }
     191                 :     }
     192                 : 
     193                 :     /*
     194                 :      * Wrappers should really be parented to the wrapped parent of the wrapped
     195                 :      * object, but in that case a wrapped global object would have a NULL
     196                 :      * parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead,
     197                 :      * we parent all wrappers to the global object in their home compartment.
     198                 :      * This loses us some transparency, and is generally very cheesy.
     199                 :      */
     200                 :     JSObject *global;
     201         2006009 :     if (cx->hasfp()) {
     202         1841496 :         global = &cx->fp()->scopeChain().global();
     203                 :     } else {
     204          164513 :         global = JS_ObjectToInnerObject(cx, cx->globalObject);
     205          164513 :         if (!global)
     206               0 :             return false;
     207                 :     }
     208                 : 
     209                 :     /* Unwrap incoming objects. */
     210         2006009 :     if (vp->isObject()) {
     211         1991804 :         JSObject *obj = &vp->toObject();
     212                 : 
     213                 :         /* If the object is already in this compartment, we are done. */
     214         1991804 :         if (obj->compartment() == this)
     215         1834480 :             return true;
     216                 : 
     217                 :         /* Translate StopIteration singleton. */
     218          157324 :         if (obj->isStopIteration())
     219               0 :             return js_FindClassObject(cx, NULL, JSProto_StopIteration, vp);
     220                 : 
     221                 :         /* Don't unwrap an outer window proxy. */
     222          157324 :         if (!obj->getClass()->ext.innerObject) {
     223          157318 :             obj = UnwrapObject(&vp->toObject(), true, &flags);
     224          157318 :             vp->setObject(*obj);
     225          157318 :             if (obj->compartment() == this)
     226           71460 :                 return true;
     227                 : 
     228           85858 :             if (cx->runtime->preWrapObjectCallback) {
     229           19477 :                 obj = cx->runtime->preWrapObjectCallback(cx, global, obj, flags);
     230           19477 :                 if (!obj)
     231               0 :                     return false;
     232                 :             }
     233                 : 
     234           85858 :             vp->setObject(*obj);
     235           85858 :             if (obj->compartment() == this)
     236             321 :                 return true;
     237                 :         } else {
     238               6 :             if (cx->runtime->preWrapObjectCallback) {
     239               3 :                 obj = cx->runtime->preWrapObjectCallback(cx, global, obj, flags);
     240               3 :                 if (!obj)
     241               0 :                     return false;
     242                 :             }
     243                 : 
     244               6 :             JS_ASSERT(!obj->isWrapper() || obj->getClass()->ext.innerObject);
     245               6 :             vp->setObject(*obj);
     246                 :         }
     247                 : 
     248                 : #ifdef DEBUG
     249                 :         {
     250           85543 :             JSObject *outer = obj;
     251           85543 :             OBJ_TO_OUTER_OBJECT(cx, outer);
     252           85543 :             JS_ASSERT(outer && outer == obj);
     253                 :         }
     254                 : #endif
     255                 :     }
     256                 : 
     257                 :     /* If we already have a wrapper for this value, use it. */
     258           99748 :     if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(*vp)) {
     259           47119 :         *vp = p->value;
     260           47119 :         if (vp->isObject()) {
     261           44399 :             JSObject *obj = &vp->toObject();
     262           44399 :             JS_ASSERT(obj->isCrossCompartmentWrapper());
     263           44399 :             if (global->getClass() != &dummy_class && obj->getParent() != global) {
     264               5 :                 do {
     265               5 :                     if (!obj->setParent(cx, global))
     266               0 :                         return false;
     267               5 :                     obj = obj->getProto();
     268               0 :                 } while (obj && obj->isCrossCompartmentWrapper());
     269                 :             }
     270                 :         }
     271           47119 :         return true;
     272                 :     }
     273                 : 
     274           52629 :     if (vp->isString()) {
     275           11485 :         Value orig = *vp;
     276           11485 :         JSString *str = vp->toString();
     277           11485 :         const jschar *chars = str->getChars(cx);
     278           11485 :         if (!chars)
     279               0 :             return false;
     280           11485 :         JSString *wrapped = js_NewStringCopyN(cx, chars, str->length());
     281           11485 :         if (!wrapped)
     282               0 :             return false;
     283           11485 :         vp->setString(wrapped);
     284           11485 :         return crossCompartmentWrappers.put(orig, *vp);
     285                 :     }
     286                 : 
     287           41144 :     JSObject *obj = &vp->toObject();
     288                 : 
     289                 :     /*
     290                 :      * Recurse to wrap the prototype. Long prototype chains will run out of
     291                 :      * stack, causing an error in CHECK_RECURSE.
     292                 :      *
     293                 :      * Wrapping the proto before creating the new wrapper and adding it to the
     294                 :      * cache helps avoid leaving a bad entry in the cache on OOM. But note that
     295                 :      * if we wrapped both proto and parent, we would get infinite recursion
     296                 :      * here (since Object.prototype->parent->proto leads to Object.prototype
     297                 :      * itself).
     298                 :      */
     299           41144 :     JSObject *proto = obj->getProto();
     300           41144 :     if (!wrap(cx, &proto))
     301              14 :         return false;
     302                 : 
     303                 :     /*
     304                 :      * We hand in the original wrapped object into the wrap hook to allow
     305                 :      * the wrap hook to reason over what wrappers are currently applied
     306                 :      * to the object.
     307                 :      */
     308           41130 :     JSObject *wrapper = cx->runtime->wrapObjectCallback(cx, obj, proto, global, flags);
     309           41130 :     if (!wrapper)
     310               9 :         return false;
     311                 : 
     312           41121 :     vp->setObject(*wrapper);
     313                 : 
     314           41121 :     if (wrapper->getProto() != proto && !SetProto(cx, wrapper, proto, false))
     315               0 :         return false;
     316                 : 
     317           41121 :     if (!crossCompartmentWrappers.put(GetProxyPrivate(wrapper), *vp))
     318               0 :         return false;
     319                 : 
     320           41121 :     if (!wrapper->setParent(cx, global))
     321               0 :         return false;
     322           41121 :     return true;
     323                 : }
     324                 : 
     325                 : bool
     326            1970 : JSCompartment::wrap(JSContext *cx, JSString **strp)
     327                 : {
     328            3940 :     AutoValueRooter tvr(cx, StringValue(*strp));
     329            1970 :     if (!wrap(cx, tvr.addr()))
     330               0 :         return false;
     331            1970 :     *strp = tvr.value().toString();
     332            1970 :     return true;
     333                 : }
     334                 : 
     335                 : bool
     336              36 : JSCompartment::wrap(JSContext *cx, HeapPtrString *strp)
     337                 : {
     338              72 :     AutoValueRooter tvr(cx, StringValue(*strp));
     339              36 :     if (!wrap(cx, tvr.addr()))
     340               0 :         return false;
     341              36 :     *strp = tvr.value().toString();
     342              36 :     return true;
     343                 : }
     344                 : 
     345                 : bool
     346         1614547 : JSCompartment::wrap(JSContext *cx, JSObject **objp)
     347                 : {
     348         1614547 :     if (!*objp)
     349            6210 :         return true;
     350         3216674 :     AutoValueRooter tvr(cx, ObjectValue(**objp));
     351         1608337 :     if (!wrap(cx, tvr.addr()))
     352              14 :         return false;
     353         1608323 :     *objp = &tvr.value().toObject();
     354         1608323 :     return true;
     355                 : }
     356                 : 
     357                 : bool
     358          430446 : JSCompartment::wrapId(JSContext *cx, jsid *idp)
     359                 : {
     360          430446 :     if (JSID_IS_INT(*idp))
     361             838 :         return true;
     362          859216 :     AutoValueRooter tvr(cx, IdToValue(*idp));
     363          429608 :     if (!wrap(cx, tvr.addr()))
     364               0 :         return false;
     365          429608 :     return ValueToId(cx, tvr.value(), idp);
     366                 : }
     367                 : 
     368                 : bool
     369              18 : JSCompartment::wrap(JSContext *cx, PropertyOp *propp)
     370                 : {
     371              18 :     Value v = CastAsObjectJsval(*propp);
     372              18 :     if (!wrap(cx, &v))
     373               0 :         return false;
     374              18 :     *propp = CastAsPropertyOp(v.toObjectOrNull());
     375              18 :     return true;
     376                 : }
     377                 : 
     378                 : bool
     379               0 : JSCompartment::wrap(JSContext *cx, StrictPropertyOp *propp)
     380                 : {
     381               0 :     Value v = CastAsObjectJsval(*propp);
     382               0 :     if (!wrap(cx, &v))
     383               0 :         return false;
     384               0 :     *propp = CastAsStrictPropertyOp(v.toObjectOrNull());
     385               0 :     return true;
     386                 : }
     387                 : 
     388                 : bool
     389              63 : JSCompartment::wrap(JSContext *cx, PropertyDescriptor *desc)
     390                 : {
     391              63 :     return wrap(cx, &desc->obj) &&
     392              81 :            (!(desc->attrs & JSPROP_GETTER) || wrap(cx, &desc->getter)) &&
     393              63 :            (!(desc->attrs & JSPROP_SETTER) || wrap(cx, &desc->setter)) &&
     394             207 :            wrap(cx, &desc->value);
     395                 : }
     396                 : 
     397                 : bool
     398               9 : JSCompartment::wrap(JSContext *cx, AutoIdVector &props)
     399                 : {
     400               9 :     jsid *vector = props.begin();
     401               9 :     int length = props.length();
     402              18 :     for (size_t n = 0; n < size_t(length); ++n) {
     403               9 :         if (!wrapId(cx, &vector[n]))
     404               0 :             return false;
     405                 :     }
     406               9 :     return true;
     407                 : }
     408                 : 
     409                 : /*
     410                 :  * This method marks pointers that cross compartment boundaries. It should be
     411                 :  * called only for per-compartment GCs, since full GCs naturally follow pointers
     412                 :  * across compartments.
     413                 :  */
     414                 : void
     415             540 : JSCompartment::markCrossCompartmentWrappers(JSTracer *trc)
     416                 : {
     417             540 :     JS_ASSERT(trc->runtime->gcCurrentCompartment);
     418                 : 
     419             927 :     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
     420             387 :         Value tmp = e.front().key;
     421             387 :         MarkValueRoot(trc, &tmp, "cross-compartment wrapper");
     422             387 :         JS_ASSERT(tmp == e.front().key);
     423                 :     }
     424             540 : }
     425                 : 
     426                 : void
     427              36 : JSCompartment::markTypes(JSTracer *trc)
     428                 : {
     429                 :     /*
     430                 :      * Mark all scripts, type objects and singleton JS objects in the
     431                 :      * compartment. These can be referred to directly by type sets, which we
     432                 :      * cannot modify while code which depends on these type sets is active.
     433                 :      */
     434              36 :     JS_ASSERT(activeAnalysis);
     435                 : 
     436             295 :     for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
     437             259 :         JSScript *script = i.get<JSScript>();
     438             259 :         MarkScriptRoot(trc, &script, "mark_types_script");
     439             259 :         JS_ASSERT(script == i.get<JSScript>());
     440                 :     }
     441                 : 
     442             468 :     for (size_t thingKind = FINALIZE_OBJECT0;
     443                 :          thingKind < FINALIZE_OBJECT_LIMIT;
     444                 :          thingKind++) {
     445           14795 :         for (CellIterUnderGC i(this, AllocKind(thingKind)); !i.done(); i.next()) {
     446           14363 :             JSObject *object = i.get<JSObject>();
     447           14363 :             if (object->hasSingletonType()) {
     448           11256 :                 MarkObjectRoot(trc, &object, "mark_types_singleton");
     449           11256 :                 JS_ASSERT(object == i.get<JSObject>());
     450                 :             }
     451                 :         }
     452                 :     }
     453                 : 
     454             590 :     for (CellIterUnderGC i(this, FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
     455             554 :         types::TypeObject *type = i.get<types::TypeObject>();
     456             554 :         MarkTypeObjectRoot(trc, &type, "mark_types_scan");
     457             554 :         JS_ASSERT(type == i.get<types::TypeObject>());
     458                 :     }
     459              36 : }
     460                 : 
     461                 : void
     462          133015 : JSCompartment::discardJitCode(JSContext *cx)
     463                 : {
     464                 :     /*
     465                 :      * Kick all frames on the stack into the interpreter, and release all JIT
     466                 :      * code in the compartment.
     467                 :      */
     468                 : #ifdef JS_METHODJIT
     469          133015 :     mjit::ClearAllFrames(this);
     470                 : 
     471         8241549 :     for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
     472         8108534 :         JSScript *script = i.get<JSScript>();
     473         8108534 :         mjit::ReleaseScriptCode(cx, script);
     474                 : 
     475                 :         /*
     476                 :          * Use counts for scripts are reset on GC. After discarding code we
     477                 :          * need to let it warm back up to get information like which opcodes
     478                 :          * are setting array holes or accessing getter properties.
     479                 :          */
     480         8108534 :         script->resetUseCount();
     481                 :     }
     482                 : #endif
     483          133015 : }
     484                 : 
     485                 : void
     486          122478 : JSCompartment::sweep(JSContext *cx, bool releaseTypes)
     487                 : {
     488                 :     /* Remove dead wrappers from the table. */
     489          180527 :     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
     490          105391 :         JS_ASSERT_IF(IsAboutToBeFinalized(e.front().key) &&
     491                 :                      !IsAboutToBeFinalized(e.front().value),
     492          105391 :                      e.front().key.isString());
     493           68781 :         if (IsAboutToBeFinalized(e.front().key) ||
     494           10732 :             IsAboutToBeFinalized(e.front().value)) {
     495           52603 :             e.removeFront();
     496                 :         }
     497                 :     }
     498                 : 
     499                 :     /* Remove dead references held weakly by the compartment. */
     500                 : 
     501          122478 :     regExps.sweep(rt);
     502                 : 
     503          122478 :     sweepBaseShapeTable(cx);
     504          122478 :     sweepInitialShapeTable(cx);
     505          122478 :     sweepNewTypeObjectTable(cx, newTypeObjects);
     506          122478 :     sweepNewTypeObjectTable(cx, lazyTypeObjects);
     507                 : 
     508          122478 :     if (emptyTypeObject && IsAboutToBeFinalized(emptyTypeObject))
     509           25653 :         emptyTypeObject = NULL;
     510                 : 
     511          122478 :     newObjectCache.reset();
     512                 : 
     513          122478 :     sweepBreakpoints(cx);
     514                 : 
     515                 :     {
     516          244956 :         gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE);
     517          122478 :         discardJitCode(cx);
     518                 :     }
     519                 : 
     520          122478 :     if (!activeAnalysis) {
     521          244884 :         gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS);
     522                 : 
     523                 :         /*
     524                 :          * Clear the analysis pool, but don't release its data yet. While
     525                 :          * sweeping types any live data will be allocated into the pool.
     526                 :          */
     527          244884 :         LifoAlloc oldAlloc(typeLifoAlloc.defaultChunkSize());
     528          122442 :         oldAlloc.steal(&typeLifoAlloc);
     529                 : 
     530                 :         /*
     531                 :          * Periodically release observed types for all scripts. This is safe to
     532                 :          * do when there are no frames for the compartment on the stack.
     533                 :          */
     534          122442 :         if (active)
     535           21178 :             releaseTypes = false;
     536                 : 
     537                 :         /*
     538                 :          * Sweep analysis information and everything depending on it from the
     539                 :          * compartment, including all remaining mjit code if inference is
     540                 :          * enabled in the compartment.
     541                 :          */
     542          122442 :         if (types.inferenceEnabled) {
     543          220611 :             for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
     544          197053 :                 JSScript *script = i.get<JSScript>();
     545          197053 :                 if (script->types) {
     546          114034 :                     types::TypeScript::Sweep(cx, script);
     547                 : 
     548          114034 :                     if (releaseTypes) {
     549              70 :                         script->types->destroy();
     550              70 :                         script->types = NULL;
     551              70 :                         script->typesPurged = true;
     552                 :                     }
     553                 :                 }
     554                 :             }
     555                 :         }
     556                 : 
     557          122442 :         types.sweep(cx);
     558                 : 
     559         8192641 :         for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
     560         8070199 :             JSScript *script = i.get<JSScript>();
     561         8070199 :             script->clearAnalysis();
     562                 :         }
     563                 :     }
     564                 : 
     565          122478 :     active = false;
     566          122478 : }
     567                 : 
     568                 : void
     569          127756 : JSCompartment::purge()
     570                 : {
     571          127756 :     dtoaCache.purge();
     572                 : 
     573                 :     /*
     574                 :      * Clear the hash and reset all evalHashLink to null before the GC. This
     575                 :      * way MarkChildren(trc, JSScript *) can assume that JSScript::u.object is
     576                 :      * not null when we have script owned by an object and not from the eval
     577                 :      * cache.
     578                 :      */
     579         8304140 :     for (size_t i = 0; i < ArrayLength(evalCache); ++i) {
     580        16386856 :         for (JSScript **listHeadp = &evalCache[i]; *listHeadp; ) {
     581           34088 :             JSScript *script = *listHeadp;
     582           34088 :             JS_ASSERT(GetGCThingTraceKind(script) == JSTRACE_SCRIPT);
     583           34088 :             *listHeadp = NULL;
     584           34088 :             listHeadp = &script->evalHashLink();
     585                 :         }
     586                 :     }
     587                 : 
     588          127756 :     nativeIterCache.purge();
     589          127756 :     toSourceCache.destroyIfConstructed();
     590          127756 : }
     591                 : 
     592                 : void
     593          168378 : JSCompartment::resetGCMallocBytes()
     594                 : {
     595          168378 :     gcMallocBytes = ptrdiff_t(gcMaxMallocBytes);
     596          168378 : }
     597                 : 
     598                 : void
     599           45576 : JSCompartment::setGCMaxMallocBytes(size_t value)
     600                 : {
     601                 :     /*
     602                 :      * For compatibility treat any value that exceeds PTRDIFF_T_MAX to
     603                 :      * mean that value.
     604                 :      */
     605           45576 :     gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
     606           45576 :     resetGCMallocBytes();
     607           45576 : }
     608                 : 
     609                 : void
     610             118 : JSCompartment::onTooMuchMalloc()
     611                 : {
     612             118 :     TriggerCompartmentGC(this, gcreason::TOO_MUCH_MALLOC);
     613             118 : }
     614                 : 
     615                 : 
     616                 : MathCache *
     617             174 : JSCompartment::allocMathCache(JSContext *cx)
     618                 : {
     619             174 :     JS_ASSERT(!mathCache);
     620             174 :     mathCache = cx->new_<MathCache>();
     621             174 :     if (!mathCache)
     622               0 :         js_ReportOutOfMemory(cx);
     623             174 :     return mathCache;
     624                 : }
     625                 : 
     626                 : bool
     627           20372 : JSCompartment::hasScriptsOnStack()
     628                 : {
     629           28106 :     for (AllFramesIter i(rt->stackSpace); !i.done(); ++i) {
     630            7746 :         JSScript *script = i.fp()->maybeScript();
     631            7746 :         if (script && script->compartment() == this)
     632              12 :             return true;
     633                 :     }
     634           20360 :     return false;
     635                 : }
     636                 : 
     637                 : bool
     638            7413 : JSCompartment::setDebugModeFromC(JSContext *cx, bool b)
     639                 : {
     640            7413 :     bool enabledBefore = debugMode();
     641            7413 :     bool enabledAfter = (debugModeBits & ~unsigned(DebugFromC)) || b;
     642                 : 
     643                 :     // Debug mode can be enabled only when no scripts from the target
     644                 :     // compartment are on the stack. It would even be incorrect to discard just
     645                 :     // the non-live scripts' JITScripts because they might share ICs with live
     646                 :     // scripts (bug 632343).
     647                 :     //
     648                 :     // We do allow disabling debug mode while scripts are on the stack.  In
     649                 :     // that case the debug-mode code for those scripts remains, so subsequently
     650                 :     // hooks may be called erroneously, even though debug mode is supposedly
     651                 :     // off, and we have to live with it.
     652                 :     //
     653            7413 :     bool onStack = false;
     654            7413 :     if (enabledBefore != enabledAfter) {
     655            7133 :         onStack = hasScriptsOnStack();
     656            7133 :         if (b && onStack) {
     657               0 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_IDLE);
     658               0 :             return false;
     659                 :         }
     660                 :     }
     661                 : 
     662            7413 :     debugModeBits = (debugModeBits & ~unsigned(DebugFromC)) | (b ? DebugFromC : 0);
     663            7413 :     JS_ASSERT(debugMode() == enabledAfter);
     664            7413 :     if (enabledBefore != enabledAfter)
     665            7133 :         updateForDebugMode(cx);
     666            7413 :     return true;
     667                 : }
     668                 : 
     669                 : void
     670           11204 : JSCompartment::updateForDebugMode(JSContext *cx)
     671                 : {
     672           21874 :     for (ContextIter acx(rt); !acx.done(); acx.next()) {
     673           10670 :         if (acx->compartment == this) 
     674            9168 :             acx->updateJITEnabled();
     675                 :     }
     676                 : 
     677                 : #ifdef JS_METHODJIT
     678           11204 :     bool enabled = debugMode();
     679                 : 
     680           11204 :     if (enabled)
     681            9168 :         JS_ASSERT(!hasScriptsOnStack());
     682            2036 :     else if (hasScriptsOnStack())
     683              12 :         return;
     684                 : 
     685                 :     /*
     686                 :      * Discard JIT code and bytecode analyses for any scripts that change
     687                 :      * debugMode.
     688                 :      */
     689           51793 :     for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
     690           40601 :         JSScript *script = i.get<JSScript>();
     691           40601 :         if (script->debugMode != enabled) {
     692           34982 :             mjit::ReleaseScriptCode(cx, script);
     693           34982 :             script->clearAnalysis();
     694           34982 :             script->debugMode = enabled;
     695                 :         }
     696                 :     }
     697                 : #endif
     698                 : }
     699                 : 
     700                 : bool
     701            3281 : JSCompartment::addDebuggee(JSContext *cx, js::GlobalObject *global)
     702                 : {
     703            3281 :     bool wasEnabled = debugMode();
     704            3281 :     if (!debuggees.put(global)) {
     705               0 :         js_ReportOutOfMemory(cx);
     706               0 :         return false;
     707                 :     }
     708            3281 :     debugModeBits |= DebugFromJS;
     709            3281 :     if (!wasEnabled)
     710            2035 :         updateForDebugMode(cx);
     711            3281 :     return true;
     712                 : }
     713                 : 
     714                 : void
     715            3281 : JSCompartment::removeDebuggee(JSContext *cx,
     716                 :                               js::GlobalObject *global,
     717                 :                               js::GlobalObjectSet::Enum *debuggeesEnum)
     718                 : {
     719            3281 :     bool wasEnabled = debugMode();
     720            3281 :     JS_ASSERT(debuggees.has(global));
     721            3281 :     if (debuggeesEnum)
     722              89 :         debuggeesEnum->removeFront();
     723                 :     else
     724            3192 :         debuggees.remove(global);
     725                 : 
     726            3281 :     if (debuggees.empty()) {
     727            3254 :         debugModeBits &= ~DebugFromJS;
     728            3254 :         if (wasEnabled && !debugMode())
     729            2036 :             updateForDebugMode(cx);
     730                 :     }
     731            3281 : }
     732                 : 
     733                 : void
     734              36 : JSCompartment::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler)
     735                 : {
     736             108 :     for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
     737              72 :         JSScript *script = i.get<JSScript>();
     738              72 :         if (script->hasAnyBreakpointsOrStepMode())
     739              36 :             script->clearBreakpointsIn(cx, dbg, handler);
     740                 :     }
     741              36 : }
     742                 : 
     743                 : void
     744           41941 : JSCompartment::clearTraps(JSContext *cx)
     745                 : {
     746          279734 :     for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
     747          237793 :         JSScript *script = i.get<JSScript>();
     748          237793 :         if (script->hasAnyBreakpointsOrStepMode())
     749             515 :             script->clearTraps(cx);
     750                 :     }
     751           41941 : }
     752                 : 
     753                 : void
     754          122478 : JSCompartment::sweepBreakpoints(JSContext *cx)
     755                 : {
     756          122478 :     if (JS_CLIST_IS_EMPTY(&cx->runtime->debuggerList))
     757          110515 :         return;
     758                 : 
     759           83734 :     for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
     760           71771 :         JSScript *script = i.get<JSScript>();
     761           71771 :         if (!script->hasAnyBreakpointsOrStepMode())
     762           71546 :             continue;
     763             225 :         bool scriptGone = IsAboutToBeFinalized(script);
     764            7389 :         for (unsigned i = 0; i < script->length; i++) {
     765            7164 :             BreakpointSite *site = script->getBreakpointSite(script->code + i);
     766            7164 :             if (!site)
     767            6840 :                 continue;
     768                 :             // nextbp is necessary here to avoid possibly reading *bp after
     769                 :             // destroying it.
     770                 :             Breakpoint *nextbp;
     771             945 :             for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
     772             621 :                 nextbp = bp->nextInSite();
     773             621 :                 if (scriptGone || IsAboutToBeFinalized(bp->debugger->toJSObject()))
     774             513 :                     bp->destroy(cx);
     775                 :             }
     776                 :         }
     777                 :     }
     778                 : }
     779                 : 
     780                 : size_t
     781               9 : JSCompartment::sizeOfShapeTable(JSMallocSizeOfFun mallocSizeOf)
     782                 : {
     783               9 :     return baseShapes.sizeOfExcludingThis(mallocSizeOf)
     784               9 :          + initialShapes.sizeOfExcludingThis(mallocSizeOf)
     785               9 :          + newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
     786              18 :          + lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
     787                 : }

Generated by: LCOV version 1.7