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

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