LCOV - code coverage report
Current view: directory - js/src - jscompartment.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 363 313 86.2 %
Date: 2012-04-07 Functions: 32 29 90.6 %

       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           41285 : JSCompartment::JSCompartment(JSRuntime *rt)
      73                 :   : rt(rt),
      74                 :     principals(NULL),
      75                 :     needsBarrier_(false),
      76                 :     gcState(NoGCScheduled),
      77                 :     gcBytes(0),
      78                 :     gcTriggerBytes(0),
      79                 :     hold(false),
      80                 :     typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
      81                 :     data(NULL),
      82                 :     active(false),
      83                 : #ifdef JS_METHODJIT
      84                 :     jaegerCompartment_(NULL),
      85                 : #endif
      86                 :     regExps(rt),
      87                 :     propertyTree(thisForCtor()),
      88                 :     emptyTypeObject(NULL),
      89                 :     gcMallocAndFreeBytes(0),
      90                 :     gcTriggerMallocAndFreeBytes(0),
      91                 :     gcMallocBytes(0),
      92                 :     debugModeBits(rt->debugMode ? DebugFromC : 0),
      93                 :     mathCache(NULL),
      94           41285 :     watchpointMap(NULL)
      95                 : {
      96           41285 :     PodArrayZero(evalCache);
      97           41285 :     setGCMaxMallocBytes(rt->gcMaxMallocBytes * 0.9);
      98           41285 : }
      99                 : 
     100           82570 : JSCompartment::~JSCompartment()
     101                 : {
     102                 :     /*
     103                 :      * Even though all objects in the compartment are dead, we may have keep
     104                 :      * some filenames around because of gcKeepAtoms.
     105                 :      */
     106           41285 :     FreeScriptFilenames(this);
     107                 : 
     108                 : #ifdef JS_METHODJIT
     109           41285 :     Foreground::delete_(jaegerCompartment_);
     110                 : #endif
     111                 : 
     112           41285 :     Foreground::delete_(mathCache);
     113           41285 :     Foreground::delete_(watchpointMap);
     114                 : 
     115                 : #ifdef DEBUG
     116         2683525 :     for (size_t i = 0; i < ArrayLength(evalCache); ++i)
     117         2642240 :         JS_ASSERT(!evalCache[i]);
     118                 : #endif
     119           41285 : }
     120                 : 
     121                 : bool
     122           41285 : JSCompartment::init(JSContext *cx)
     123                 : {
     124           41285 :     activeAnalysis = activeInference = false;
     125           41285 :     types.init(cx);
     126                 : 
     127           41285 :     newObjectCache.reset();
     128                 : 
     129           41285 :     if (!crossCompartmentWrappers.init())
     130               0 :         return false;
     131                 : 
     132           41285 :     if (!regExps.init(cx))
     133               0 :         return false;
     134                 : 
     135           41285 :     if (!scriptFilenameTable.init())
     136               0 :         return false;
     137                 : 
     138           41285 :     return debuggees.init();
     139                 : }
     140                 : 
     141                 : #ifdef JS_METHODJIT
     142                 : bool
     143        12505470 : JSCompartment::ensureJaegerCompartmentExists(JSContext *cx)
     144                 : {
     145        12505470 :     if (jaegerCompartment_)
     146        12494480 :         return true;
     147                 : 
     148           10990 :     mjit::JaegerCompartment *jc = cx->new_<mjit::JaegerCompartment>();
     149           10990 :     if (!jc)
     150               0 :         return false;
     151           10990 :     if (!jc->Initialize(cx)) {
     152               0 :         cx->delete_(jc);
     153               0 :         return false;
     154                 :     }
     155           10990 :     jaegerCompartment_ = jc;
     156           10990 :     return true;
     157                 : }
     158                 : 
     159                 : size_t
     160               0 : JSCompartment::sizeOfMjitCode() const
     161                 : {
     162               0 :     if (!jaegerCompartment_)
     163               0 :         return 0;
     164                 : 
     165                 :     size_t method, regexp, unused;
     166               0 :     jaegerCompartment_->execAlloc()->sizeOfCode(&method, &regexp, &unused);
     167               0 :     JS_ASSERT(regexp == 0);
     168               0 :     return method + unused;
     169                 : }
     170                 : 
     171                 : #endif
     172                 : 
     173                 : bool
     174         6192726 : JSCompartment::wrap(JSContext *cx, Value *vp)
     175                 : {
     176         6192726 :     JS_ASSERT(cx->compartment == this);
     177                 : 
     178         6192726 :     unsigned flags = 0;
     179                 : 
     180         6192726 :     JS_CHECK_RECURSION(cx, return false);
     181                 : 
     182                 :     /* Only GC things have to be wrapped or copied. */
     183         5728253 :     if (!vp->isMarkable())
     184         3900359 :         return true;
     185                 : 
     186         1827894 :     if (vp->isString()) {
     187          892311 :         JSString *str = vp->toString();
     188                 : 
     189                 :         /* If the string is already in this compartment, we are done. */
     190          892311 :         if (str->compartment() == this)
     191             639 :             return true;
     192                 : 
     193                 :         /* If the string is an atom, we don't have to copy. */
     194          891672 :         if (str->isAtom()) {
     195          878312 :             JS_ASSERT(str->compartment() == cx->runtime->atomsCompartment);
     196          878312 :             return true;
     197                 :         }
     198                 :     }
     199                 : 
     200                 :     /*
     201                 :      * Wrappers should really be parented to the wrapped parent of the wrapped
     202                 :      * object, but in that case a wrapped global object would have a NULL
     203                 :      * parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead,
     204                 :      * we parent all wrappers to the global object in their home compartment.
     205                 :      * This loses us some transparency, and is generally very cheesy.
     206                 :      */
     207                 :     JSObject *global;
     208          948943 :     if (cx->hasfp()) {
     209          929552 :         global = &cx->fp()->scopeChain().global();
     210                 :     } else {
     211           19391 :         global = JS_ObjectToInnerObject(cx, cx->globalObject);
     212           19391 :         if (!global)
     213               0 :             return false;
     214                 :     }
     215                 : 
     216                 :     /* Unwrap incoming objects. */
     217          948943 :     if (vp->isObject()) {
     218          935583 :         JSObject *obj = &vp->toObject();
     219                 : 
     220                 :         /* If the object is already in this compartment, we are done. */
     221          935583 :         if (obj->compartment() == this)
     222          741375 :             return true;
     223                 : 
     224                 :         /* Translate StopIteration singleton. */
     225          194208 :         if (obj->isStopIteration())
     226               0 :             return js_FindClassObject(cx, NULL, JSProto_StopIteration, vp);
     227                 : 
     228                 :         /* Don't unwrap an outer window proxy. */
     229          194208 :         if (!obj->getClass()->ext.innerObject) {
     230          194202 :             obj = UnwrapObject(&vp->toObject(), true, &flags);
     231          194202 :             vp->setObject(*obj);
     232          194202 :             if (obj->compartment() == this)
     233           96343 :                 return true;
     234                 : 
     235           97859 :             if (cx->runtime->preWrapObjectCallback) {
     236               0 :                 obj = cx->runtime->preWrapObjectCallback(cx, global, obj, flags);
     237               0 :                 if (!obj)
     238               0 :                     return false;
     239                 :             }
     240                 : 
     241           97859 :             vp->setObject(*obj);
     242           97859 :             if (obj->compartment() == this)
     243               0 :                 return true;
     244                 :         } else {
     245               6 :             if (cx->runtime->preWrapObjectCallback) {
     246               3 :                 obj = cx->runtime->preWrapObjectCallback(cx, global, obj, flags);
     247               3 :                 if (!obj)
     248               0 :                     return false;
     249                 :             }
     250                 : 
     251               6 :             JS_ASSERT(!obj->isWrapper() || obj->getClass()->ext.innerObject);
     252               6 :             vp->setObject(*obj);
     253                 :         }
     254                 : 
     255                 : #ifdef DEBUG
     256                 :         {
     257           97865 :             JSObject *outer = obj;
     258           97865 :             OBJ_TO_OUTER_OBJECT(cx, outer);
     259           97865 :             JS_ASSERT(outer && outer == obj);
     260                 :         }
     261                 : #endif
     262                 :     }
     263                 : 
     264                 :     /* If we already have a wrapper for this value, use it. */
     265          111225 :     if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(*vp)) {
     266           66063 :         *vp = p->value;
     267           66063 :         if (vp->isObject()) {
     268           63335 :             JSObject *obj = &vp->toObject();
     269           63335 :             JS_ASSERT(obj->isCrossCompartmentWrapper());
     270           63335 :             if (global->getClass() != &dummy_class && obj->getParent() != global) {
     271               0 :                 do {
     272               0 :                     if (!obj->setParent(cx, global))
     273               0 :                         return false;
     274               0 :                     obj = obj->getProto();
     275               0 :                 } while (obj && obj->isCrossCompartmentWrapper());
     276                 :             }
     277                 :         }
     278           66063 :         return true;
     279                 :     }
     280                 : 
     281           45162 :     if (vp->isString()) {
     282           10632 :         Value orig = *vp;
     283           10632 :         JSString *str = vp->toString();
     284           10632 :         const jschar *chars = str->getChars(cx);
     285           10632 :         if (!chars)
     286               0 :             return false;
     287           10632 :         JSString *wrapped = js_NewStringCopyN(cx, chars, str->length());
     288           10632 :         if (!wrapped)
     289               0 :             return false;
     290           10632 :         vp->setString(wrapped);
     291           10632 :         return crossCompartmentWrappers.put(orig, *vp);
     292                 :     }
     293                 : 
     294           34530 :     JSObject *obj = &vp->toObject();
     295                 : 
     296                 :     /*
     297                 :      * Recurse to wrap the prototype. Long prototype chains will run out of
     298                 :      * stack, causing an error in CHECK_RECURSE.
     299                 :      *
     300                 :      * Wrapping the proto before creating the new wrapper and adding it to the
     301                 :      * cache helps avoid leaving a bad entry in the cache on OOM. But note that
     302                 :      * if we wrapped both proto and parent, we would get infinite recursion
     303                 :      * here (since Object.prototype->parent->proto leads to Object.prototype
     304                 :      * itself).
     305                 :      */
     306           34530 :     JSObject *proto = obj->getProto();
     307           34530 :     if (!wrap(cx, &proto))
     308              11 :         return false;
     309                 : 
     310                 :     /*
     311                 :      * We hand in the original wrapped object into the wrap hook to allow
     312                 :      * the wrap hook to reason over what wrappers are currently applied
     313                 :      * to the object.
     314                 :      */
     315           34519 :     JSObject *wrapper = cx->runtime->wrapObjectCallback(cx, obj, proto, global, flags);
     316           34519 :     if (!wrapper)
     317               9 :         return false;
     318                 : 
     319           34510 :     vp->setObject(*wrapper);
     320                 : 
     321           34510 :     if (wrapper->getProto() != proto && !SetProto(cx, wrapper, proto, false))
     322               0 :         return false;
     323                 : 
     324           34510 :     if (!crossCompartmentWrappers.put(GetProxyPrivate(wrapper), *vp))
     325               0 :         return false;
     326                 : 
     327           34510 :     if (!wrapper->setParent(cx, global))
     328               0 :         return false;
     329           34510 :     return true;
     330                 : }
     331                 : 
     332                 : bool
     333            1944 : JSCompartment::wrap(JSContext *cx, JSString **strp)
     334                 : {
     335            3888 :     AutoValueRooter tvr(cx, StringValue(*strp));
     336            1944 :     if (!wrap(cx, tvr.addr()))
     337               0 :         return false;
     338            1944 :     *strp = tvr.value().toString();
     339            1944 :     return true;
     340                 : }
     341                 : 
     342                 : bool
     343              36 : JSCompartment::wrap(JSContext *cx, HeapPtrString *strp)
     344                 : {
     345              72 :     AutoValueRooter tvr(cx, StringValue(*strp));
     346              36 :     if (!wrap(cx, tvr.addr()))
     347               0 :         return false;
     348              36 :     *strp = tvr.value().toString();
     349              36 :     return true;
     350                 : }
     351                 : 
     352                 : bool
     353          129061 : JSCompartment::wrap(JSContext *cx, JSObject **objp)
     354                 : {
     355          129061 :     if (!*objp)
     356            5051 :         return true;
     357          248020 :     AutoValueRooter tvr(cx, ObjectValue(**objp));
     358          124010 :     if (!wrap(cx, tvr.addr()))
     359              11 :         return false;
     360          123999 :     *objp = &tvr.value().toObject();
     361          123999 :     return true;
     362                 : }
     363                 : 
     364                 : bool
     365          585292 : JSCompartment::wrapId(JSContext *cx, jsid *idp)
     366                 : {
     367          585292 :     if (JSID_IS_INT(*idp))
     368           18477 :         return true;
     369         1133630 :     AutoValueRooter tvr(cx, IdToValue(*idp));
     370          566815 :     if (!wrap(cx, tvr.addr()))
     371               0 :         return false;
     372          566815 :     return ValueToId(cx, tvr.value(), idp);
     373                 : }
     374                 : 
     375                 : bool
     376              18 : JSCompartment::wrap(JSContext *cx, PropertyOp *propp)
     377                 : {
     378              18 :     Value v = CastAsObjectJsval(*propp);
     379              18 :     if (!wrap(cx, &v))
     380               0 :         return false;
     381              18 :     *propp = CastAsPropertyOp(v.toObjectOrNull());
     382              18 :     return true;
     383                 : }
     384                 : 
     385                 : bool
     386               0 : JSCompartment::wrap(JSContext *cx, StrictPropertyOp *propp)
     387                 : {
     388               0 :     Value v = CastAsObjectJsval(*propp);
     389               0 :     if (!wrap(cx, &v))
     390               0 :         return false;
     391               0 :     *propp = CastAsStrictPropertyOp(v.toObjectOrNull());
     392               0 :     return true;
     393                 : }
     394                 : 
     395                 : bool
     396              63 : JSCompartment::wrap(JSContext *cx, PropertyDescriptor *desc)
     397                 : {
     398              63 :     return wrap(cx, &desc->obj) &&
     399              81 :            (!(desc->attrs & JSPROP_GETTER) || wrap(cx, &desc->getter)) &&
     400              63 :            (!(desc->attrs & JSPROP_SETTER) || wrap(cx, &desc->setter)) &&
     401             207 :            wrap(cx, &desc->value);
     402                 : }
     403                 : 
     404                 : bool
     405           22419 : JSCompartment::wrap(JSContext *cx, AutoIdVector &props)
     406                 : {
     407           22419 :     jsid *vector = props.begin();
     408           22419 :     int length = props.length();
     409           45918 :     for (size_t n = 0; n < size_t(length); ++n) {
     410           23499 :         if (!wrapId(cx, &vector[n]))
     411               0 :             return false;
     412                 :     }
     413           22419 :     return true;
     414                 : }
     415                 : 
     416                 : /*
     417                 :  * This method marks pointers that cross compartment boundaries. It should be
     418                 :  * called only for per-compartment GCs, since full GCs naturally follow pointers
     419                 :  * across compartments.
     420                 :  */
     421                 : void
     422             324 : JSCompartment::markCrossCompartmentWrappers(JSTracer *trc)
     423                 : {
     424             324 :     JS_ASSERT(!isCollecting());
     425                 : 
     426             630 :     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
     427             306 :         Value tmp = e.front().key;
     428             306 :         MarkValueRoot(trc, &tmp, "cross-compartment wrapper");
     429             306 :         JS_ASSERT(tmp == e.front().key);
     430                 :     }
     431             324 : }
     432                 : 
     433                 : void
     434              20 : JSCompartment::markTypes(JSTracer *trc)
     435                 : {
     436                 :     /*
     437                 :      * Mark all scripts, type objects and singleton JS objects in the
     438                 :      * compartment. These can be referred to directly by type sets, which we
     439                 :      * cannot modify while code which depends on these type sets is active.
     440                 :      */
     441              20 :     JS_ASSERT(activeAnalysis);
     442                 : 
     443             241 :     for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
     444             221 :         JSScript *script = i.get<JSScript>();
     445             221 :         MarkScriptRoot(trc, &script, "mark_types_script");
     446             221 :         JS_ASSERT(script == i.get<JSScript>());
     447                 :     }
     448                 : 
     449             260 :     for (size_t thingKind = FINALIZE_OBJECT0;
     450                 :          thingKind < FINALIZE_OBJECT_LIMIT;
     451                 :          thingKind++) {
     452            8831 :         for (CellIterUnderGC i(this, AllocKind(thingKind)); !i.done(); i.next()) {
     453            8591 :             JSObject *object = i.get<JSObject>();
     454            8591 :             if (object->hasSingletonType()) {
     455            6742 :                 MarkObjectRoot(trc, &object, "mark_types_singleton");
     456            6742 :                 JS_ASSERT(object == i.get<JSObject>());
     457                 :             }
     458                 :         }
     459                 :     }
     460                 : 
     461             380 :     for (CellIterUnderGC i(this, FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
     462             360 :         types::TypeObject *type = i.get<types::TypeObject>();
     463             360 :         MarkTypeObjectRoot(trc, &type, "mark_types_scan");
     464             360 :         JS_ASSERT(type == i.get<types::TypeObject>());
     465                 :     }
     466              20 : }
     467                 : 
     468                 : void
     469           94341 : JSCompartment::discardJitCode(FreeOp *fop)
     470                 : {
     471                 :     /*
     472                 :      * Kick all frames on the stack into the interpreter, and release all JIT
     473                 :      * code in the compartment.
     474                 :      */
     475                 : #ifdef JS_METHODJIT
     476           94341 :     mjit::ClearAllFrames(this);
     477                 : 
     478          549656 :     for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
     479          455315 :         JSScript *script = i.get<JSScript>();
     480          455315 :         mjit::ReleaseScriptCode(fop, script);
     481                 : 
     482                 :         /*
     483                 :          * Use counts for scripts are reset on GC. After discarding code we
     484                 :          * need to let it warm back up to get information like which opcodes
     485                 :          * are setting array holes or accessing getter properties.
     486                 :          */
     487          455315 :         script->resetUseCount();
     488                 :     }
     489                 : #endif
     490           94341 : }
     491                 : 
     492                 : void
     493           83697 : JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
     494                 : {
     495                 :     /* Remove dead wrappers from the table. */
     496          139657 :     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
     497           99909 :         JS_ASSERT_IF(IsAboutToBeFinalized(e.front().key) &&
     498                 :                      !IsAboutToBeFinalized(e.front().value),
     499           99909 :                      e.front().key.isString());
     500           67972 :         if (IsAboutToBeFinalized(e.front().key) ||
     501           12012 :             IsAboutToBeFinalized(e.front().value)) {
     502           45139 :             e.removeFront();
     503                 :         }
     504                 :     }
     505                 : 
     506                 :     /* Remove dead references held weakly by the compartment. */
     507                 : 
     508           83697 :     regExps.sweep(rt);
     509                 : 
     510           83697 :     sweepBaseShapeTable();
     511           83697 :     sweepInitialShapeTable();
     512           83697 :     sweepNewTypeObjectTable(newTypeObjects);
     513           83697 :     sweepNewTypeObjectTable(lazyTypeObjects);
     514                 : 
     515           83697 :     if (emptyTypeObject && IsAboutToBeFinalized(emptyTypeObject))
     516           22524 :         emptyTypeObject = NULL;
     517                 : 
     518           83697 :     newObjectCache.reset();
     519                 : 
     520           83697 :     sweepBreakpoints(fop);
     521                 : 
     522                 :     {
     523          167394 :         gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE);
     524           83697 :         discardJitCode(fop);
     525                 :     }
     526                 : 
     527           83697 :     if (!activeAnalysis) {
     528          167354 :         gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS);
     529                 : 
     530                 :         /*
     531                 :          * Clear the analysis pool, but don't release its data yet. While
     532                 :          * sweeping types any live data will be allocated into the pool.
     533                 :          */
     534          167354 :         LifoAlloc oldAlloc(typeLifoAlloc.defaultChunkSize());
     535           83677 :         oldAlloc.steal(&typeLifoAlloc);
     536                 : 
     537                 :         /*
     538                 :          * Periodically release observed types for all scripts. This is safe to
     539                 :          * do when there are no frames for the compartment on the stack.
     540                 :          */
     541           83677 :         if (active)
     542           21606 :             releaseTypes = false;
     543                 : 
     544                 :         /*
     545                 :          * Sweep analysis information and everything depending on it from the
     546                 :          * compartment, including all remaining mjit code if inference is
     547                 :          * enabled in the compartment.
     548                 :          */
     549           83677 :         if (types.inferenceEnabled) {
     550           49284 :             gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_TI);
     551                 : 
     552          249934 :             for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
     553          225292 :                 JSScript *script = i.get<JSScript>();
     554          225292 :                 if (script->types) {
     555          117460 :                     types::TypeScript::Sweep(fop, script);
     556                 : 
     557          117460 :                     if (releaseTypes) {
     558              70 :                         script->types->destroy();
     559              70 :                         script->types = NULL;
     560              70 :                         script->typesPurged = true;
     561                 :                     }
     562                 :                 }
     563                 :             }
     564                 :         }
     565                 : 
     566                 :         {
     567          167354 :             gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_TYPES);
     568           83677 :             types.sweep(fop);
     569                 :         }
     570                 : 
     571                 :         {
     572          167354 :             gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_CLEAR_SCRIPT_ANALYSIS);
     573          495754 :             for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
     574          412077 :                 JSScript *script = i.get<JSScript>();
     575          412077 :                 script->clearAnalysis();
     576                 :             }
     577                 :         }
     578                 :     }
     579                 : 
     580           83697 :     active = false;
     581           83697 : }
     582                 : 
     583                 : void
     584           89042 : JSCompartment::purge()
     585                 : {
     586           89042 :     dtoaCache.purge();
     587                 : 
     588                 :     /*
     589                 :      * Clear the hash and reset all evalHashLink to null before the GC. This
     590                 :      * way MarkChildren(trc, JSScript *) can assume that JSScript::u.object is
     591                 :      * not null when we have script owned by an object and not from the eval
     592                 :      * cache.
     593                 :      */
     594         5787730 :     for (size_t i = 0; i < ArrayLength(evalCache); ++i) {
     595        11431367 :         for (JSScript **listHeadp = &evalCache[i]; *listHeadp; ) {
     596           33991 :             JSScript *script = *listHeadp;
     597           33991 :             JS_ASSERT(GetGCThingTraceKind(script) == JSTRACE_SCRIPT);
     598           33991 :             *listHeadp = NULL;
     599           33991 :             listHeadp = &script->evalHashLink();
     600                 :         }
     601                 :     }
     602                 : 
     603           89042 :     nativeIterCache.purge();
     604           89042 :     toSourceCache.destroyIfConstructed();
     605           89042 : }
     606                 : 
     607                 : void
     608          125423 : JSCompartment::resetGCMallocBytes()
     609                 : {
     610          125423 :     gcMallocBytes = ptrdiff_t(gcMaxMallocBytes);
     611          125423 : }
     612                 : 
     613                 : void
     614           41285 : JSCompartment::setGCMaxMallocBytes(size_t value)
     615                 : {
     616                 :     /*
     617                 :      * For compatibility treat any value that exceeds PTRDIFF_T_MAX to
     618                 :      * mean that value.
     619                 :      */
     620           41285 :     gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
     621           41285 :     resetGCMallocBytes();
     622           41285 : }
     623                 : 
     624                 : void
     625             108 : JSCompartment::onTooMuchMalloc()
     626                 : {
     627             108 :     TriggerCompartmentGC(this, gcreason::TOO_MUCH_MALLOC);
     628             108 : }
     629                 : 
     630                 : 
     631                 : MathCache *
     632             183 : JSCompartment::allocMathCache(JSContext *cx)
     633                 : {
     634             183 :     JS_ASSERT(!mathCache);
     635             183 :     mathCache = cx->new_<MathCache>();
     636             183 :     if (!mathCache)
     637               0 :         js_ReportOutOfMemory(cx);
     638             183 :     return mathCache;
     639                 : }
     640                 : 
     641                 : bool
     642           19525 : JSCompartment::hasScriptsOnStack()
     643                 : {
     644           26842 :     for (AllFramesIter i(rt->stackSpace); !i.done(); ++i) {
     645            7329 :         JSScript *script = i.fp()->maybeScript();
     646            7329 :         if (script && script->compartment() == this)
     647              12 :             return true;
     648                 :     }
     649           19513 :     return false;
     650                 : }
     651                 : 
     652                 : bool
     653            6940 : JSCompartment::setDebugModeFromC(JSContext *cx, bool b)
     654                 : {
     655            6940 :     bool enabledBefore = debugMode();
     656            6940 :     bool enabledAfter = (debugModeBits & ~unsigned(DebugFromC)) || b;
     657                 : 
     658                 :     // Debug mode can be enabled only when no scripts from the target
     659                 :     // compartment are on the stack. It would even be incorrect to discard just
     660                 :     // the non-live scripts' JITScripts because they might share ICs with live
     661                 :     // scripts (bug 632343).
     662                 :     //
     663                 :     // We do allow disabling debug mode while scripts are on the stack.  In
     664                 :     // that case the debug-mode code for those scripts remains, so subsequently
     665                 :     // hooks may be called erroneously, even though debug mode is supposedly
     666                 :     // off, and we have to live with it.
     667                 :     //
     668            6940 :     bool onStack = false;
     669            6940 :     if (enabledBefore != enabledAfter) {
     670            6660 :         onStack = hasScriptsOnStack();
     671            6660 :         if (b && onStack) {
     672               0 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_IDLE);
     673               0 :             return false;
     674                 :         }
     675                 :     }
     676                 : 
     677            6940 :     debugModeBits = (debugModeBits & ~unsigned(DebugFromC)) | (b ? DebugFromC : 0);
     678            6940 :     JS_ASSERT(debugMode() == enabledAfter);
     679            6940 :     if (enabledBefore != enabledAfter)
     680            6660 :         updateForDebugMode(cx->runtime->defaultFreeOp());
     681            6940 :     return true;
     682                 : }
     683                 : 
     684                 : void
     685           10797 : JSCompartment::updateForDebugMode(FreeOp *fop)
     686                 : {
     687           19682 :     for (ContextIter acx(rt); !acx.done(); acx.next()) {
     688            8885 :         if (acx->compartment == this) 
     689            8728 :             acx->updateJITEnabled();
     690                 :     }
     691                 : 
     692                 : #ifdef JS_METHODJIT
     693           10797 :     bool enabled = debugMode();
     694                 : 
     695           10797 :     if (enabled)
     696            8728 :         JS_ASSERT(!hasScriptsOnStack());
     697            2069 :     else if (hasScriptsOnStack())
     698              12 :         return;
     699                 : 
     700                 :     /*
     701                 :      * Discard JIT code and bytecode analyses for any scripts that change
     702                 :      * debugMode.
     703                 :      */
     704           32717 :     for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
     705           21932 :         JSScript *script = i.get<JSScript>();
     706           21932 :         if (script->debugMode != enabled) {
     707           16345 :             mjit::ReleaseScriptCode(fop, script);
     708           16345 :             script->clearAnalysis();
     709           16345 :             script->debugMode = enabled;
     710                 :         }
     711                 :     }
     712                 : #endif
     713                 : }
     714                 : 
     715                 : bool
     716            3353 : JSCompartment::addDebuggee(JSContext *cx, js::GlobalObject *global)
     717                 : {
     718            3353 :     bool wasEnabled = debugMode();
     719            3353 :     if (!debuggees.put(global)) {
     720               0 :         js_ReportOutOfMemory(cx);
     721               0 :         return false;
     722                 :     }
     723            3353 :     debugModeBits |= DebugFromJS;
     724            3353 :     if (!wasEnabled)
     725            2068 :         updateForDebugMode(cx->runtime->defaultFreeOp());
     726            3353 :     return true;
     727                 : }
     728                 : 
     729                 : void
     730            3353 : JSCompartment::removeDebuggee(FreeOp *fop,
     731                 :                               js::GlobalObject *global,
     732                 :                               js::GlobalObjectSet::Enum *debuggeesEnum)
     733                 : {
     734            3353 :     bool wasEnabled = debugMode();
     735            3353 :     JS_ASSERT(debuggees.has(global));
     736            3353 :     if (debuggeesEnum)
     737              90 :         debuggeesEnum->removeFront();
     738                 :     else
     739            3263 :         debuggees.remove(global);
     740                 : 
     741            3353 :     if (debuggees.empty()) {
     742            3326 :         debugModeBits &= ~DebugFromJS;
     743            3326 :         if (wasEnabled && !debugMode())
     744            2069 :             updateForDebugMode(fop);
     745                 :     }
     746            3353 : }
     747                 : 
     748                 : void
     749              36 : JSCompartment::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler)
     750                 : {
     751             108 :     for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
     752              72 :         JSScript *script = i.get<JSScript>();
     753              72 :         if (script->hasAnyBreakpointsOrStepMode())
     754              36 :             script->clearBreakpointsIn(cx, dbg, handler);
     755                 :     }
     756              36 : }
     757                 : 
     758                 : void
     759           41261 : JSCompartment::clearTraps(JSContext *cx)
     760                 : {
     761          316723 :     for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
     762          275462 :         JSScript *script = i.get<JSScript>();
     763          275462 :         if (script->hasAnyBreakpointsOrStepMode())
     764             515 :             script->clearTraps(cx->runtime->defaultFreeOp());
     765                 :     }
     766           41261 : }
     767                 : 
     768                 : void
     769           83697 : JSCompartment::sweepBreakpoints(FreeOp *fop)
     770                 : {
     771           83697 :     if (JS_CLIST_IS_EMPTY(&rt->debuggerList))
     772           71619 :         return;
     773                 : 
     774           74531 :     for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
     775           62453 :         JSScript *script = i.get<JSScript>();
     776           62453 :         if (!script->hasAnyBreakpointsOrStepMode())
     777           62228 :             continue;
     778             225 :         bool scriptGone = IsAboutToBeFinalized(script);
     779            7398 :         for (unsigned i = 0; i < script->length; i++) {
     780            7173 :             BreakpointSite *site = script->getBreakpointSite(script->code + i);
     781            7173 :             if (!site)
     782            6849 :                 continue;
     783                 :             // nextbp is necessary here to avoid possibly reading *bp after
     784                 :             // destroying it.
     785                 :             Breakpoint *nextbp;
     786             945 :             for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
     787             621 :                 nextbp = bp->nextInSite();
     788             621 :                 if (scriptGone || IsAboutToBeFinalized(bp->debugger->toJSObject()))
     789             513 :                     bp->destroy(fop);
     790                 :             }
     791                 :         }
     792                 :     }
     793                 : }
     794                 : 
     795                 : size_t
     796               0 : JSCompartment::sizeOfShapeTable(JSMallocSizeOfFun mallocSizeOf)
     797                 : {
     798               0 :     return baseShapes.sizeOfExcludingThis(mallocSizeOf)
     799               0 :          + initialShapes.sizeOfExcludingThis(mallocSizeOf)
     800               0 :          + newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
     801               0 :          + lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
     802                 : }

Generated by: LCOV version 1.7