LCOV - code coverage report
Current view: top level - js/src/vm - JSContext-inl.h (source / functions) Hit Total Coverage
Test: output.info Lines: 33 228 14.5 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef vm_JSContext_inl_h
       8             : #define vm_JSContext_inl_h
       9             : 
      10             : #include "vm/JSContext.h"
      11             : 
      12             : #include "builtin/Object.h"
      13             : #include "jit/JitFrames.h"
      14             : #include "proxy/Proxy.h"
      15             : #include "vm/HelperThreads.h"
      16             : #include "vm/Interpreter.h"
      17             : #include "vm/Iteration.h"
      18             : #include "vm/Realm.h"
      19             : #include "vm/SymbolType.h"
      20             : 
      21             : namespace js {
      22             : 
      23             : class CompartmentChecker
      24             : {
      25             :     JS::Compartment* compartment;
      26             : 
      27             :   public:
      28             :     explicit CompartmentChecker(JSContext* cx)
      29           0 :       : compartment(cx->compartment())
      30             :     {
      31             :     }
      32             : 
      33             :     /*
      34             :      * Set a breakpoint here (break js::CompartmentChecker::fail) to debug
      35             :      * compartment mismatches.
      36             :      */
      37           0 :     static void fail(JS::Compartment* c1, JS::Compartment* c2) {
      38           0 :         printf("*** Compartment mismatch %p vs. %p\n", (void*) c1, (void*) c2);
      39           0 :         MOZ_CRASH();
      40             :     }
      41             : 
      42           0 :     static void fail(JS::Zone* z1, JS::Zone* z2) {
      43           0 :         printf("*** Zone mismatch %p vs. %p\n", (void*) z1, (void*) z2);
      44           0 :         MOZ_CRASH();
      45             :     }
      46             : 
      47             :     static void check(JS::Compartment* c1, JS::Compartment* c2) {
      48             :         if (c1 != c2)
      49             :             fail(c1, c2);
      50             :     }
      51             : 
      52             :     void check(JS::Compartment* c) {
      53           0 :         if (c && c != compartment)
      54           0 :             fail(compartment, c);
      55             :     }
      56             : 
      57           0 :     void checkZone(JS::Zone* z) {
      58           0 :         if (compartment && z != compartment->zone())
      59           0 :             fail(compartment->zone(), z);
      60           0 :     }
      61             : 
      62           0 :     void check(JSObject* obj) {
      63           0 :         if (obj) {
      64           0 :             MOZ_ASSERT(JS::ObjectIsNotGray(obj));
      65           0 :             MOZ_ASSERT(!js::gc::IsAboutToBeFinalizedUnbarriered(&obj));
      66           0 :             check(obj->compartment());
      67             :         }
      68           0 :     }
      69             : 
      70             :     template<typename T>
      71             :     void check(const Rooted<T>& rooted) {
      72           0 :         check(rooted.get());
      73             :     }
      74             : 
      75             :     template<typename T>
      76             :     void check(Handle<T> handle) {
      77           0 :         check(handle.get());
      78             :     }
      79             : 
      80             :     template<typename T>
      81             :     void check(MutableHandle<T> handle) {
      82           0 :         check(handle.get());
      83             :     }
      84             : 
      85             :     template <typename T>
      86           0 :     void checkAtom(T* thing) {
      87             :         static_assert(mozilla::IsSame<T, JSAtom>::value ||
      88             :                       mozilla::IsSame<T, JS::Symbol>::value,
      89             :                       "Should only be called with JSAtom* or JS::Symbol* argument");
      90             : 
      91             : #ifdef DEBUG
      92             :         // Atoms which move across zone boundaries need to be marked in the new
      93             :         // zone, see JS_MarkCrossZoneId.
      94           0 :         if (compartment) {
      95           0 :             JSRuntime* rt = compartment->runtimeFromAnyThread();
      96           0 :             MOZ_ASSERT(rt->gc.atomMarking.atomIsMarked(compartment->zone(), thing));
      97             :         }
      98             : #endif
      99           0 :     }
     100             : 
     101           0 :     void check(JSString* str) {
     102           0 :         MOZ_ASSERT(JS::CellIsNotGray(str));
     103           0 :         if (str->isAtom()) {
     104           0 :             checkAtom(&str->asAtom());
     105             :         } else {
     106           0 :             checkZone(str->zone());
     107             :         }
     108           0 :     }
     109             : 
     110             :     void check(JS::Symbol* symbol) {
     111           0 :         checkAtom(symbol);
     112             :     }
     113             : 
     114           0 :     void check(const js::Value& v) {
     115           0 :         if (v.isObject())
     116           0 :             check(&v.toObject());
     117           0 :         else if (v.isString())
     118           0 :             check(v.toString());
     119           0 :         else if (v.isSymbol())
     120           0 :             check(v.toSymbol());
     121           0 :     }
     122             : 
     123             :     // Check the contents of any container class that supports the C++
     124             :     // iteration protocol, eg GCVector<jsid>.
     125             :     template <typename Container>
     126             :     typename mozilla::EnableIf<
     127             :         mozilla::IsSame<
     128             :             decltype(((Container*)nullptr)->begin()),
     129             :             decltype(((Container*)nullptr)->end())
     130             :         >::value
     131             :     >::Type
     132           0 :     check(const Container& container) {
     133           0 :         for (auto i : container)
     134           0 :             check(i);
     135           0 :     }
     136             : 
     137           0 :     void check(const JS::HandleValueArray& arr) {
     138           0 :         for (size_t i = 0; i < arr.length(); i++)
     139           0 :             check(arr[i]);
     140           0 :     }
     141             : 
     142           0 :     void check(const CallArgs& args) {
     143           0 :         for (Value* p = args.base(); p != args.end(); ++p)
     144           0 :             check(*p);
     145           0 :     }
     146             : 
     147           0 :     void check(jsid id) {
     148           0 :         if (JSID_IS_ATOM(id))
     149           0 :             checkAtom(JSID_TO_ATOM(id));
     150           0 :         else if (JSID_IS_SYMBOL(id))
     151           0 :             checkAtom(JSID_TO_SYMBOL(id));
     152             :         else
     153             :             MOZ_ASSERT(!JSID_IS_GCTHING(id));
     154           0 :     }
     155             : 
     156           0 :     void check(JSScript* script) {
     157           0 :         MOZ_ASSERT(JS::CellIsNotGray(script));
     158           0 :         if (script)
     159           0 :             check(script->compartment());
     160           0 :     }
     161             : 
     162             :     void check(InterpreterFrame* fp);
     163             :     void check(AbstractFramePtr frame);
     164             : 
     165           0 :     void check(Handle<PropertyDescriptor> desc) {
     166           0 :         check(desc.object());
     167           0 :         if (desc.hasGetterObject())
     168           0 :             check(desc.getterObject());
     169           0 :         if (desc.hasSetterObject())
     170           0 :             check(desc.setterObject());
     171           0 :         check(desc.value());
     172           0 :     }
     173             : 
     174           0 :     void check(TypeSet::Type type) {
     175           0 :         check(type.maybeCompartment());
     176           0 :     }
     177             : };
     178             : 
     179             : /*
     180             :  * Don't perform these checks when called from a finalizer. The checking
     181             :  * depends on other objects not having been swept yet.
     182             :  */
     183             : #define START_ASSERT_SAME_COMPARTMENT()                                 \
     184             :     if (JS::RuntimeHeapIsCollecting())                            \
     185             :         return;                                                         \
     186             :     CompartmentChecker c(cx)
     187             : 
     188             : template <class T1> inline void
     189           0 : releaseAssertSameCompartment(JSContext* cx, const T1& t1)
     190             : {
     191           0 :     START_ASSERT_SAME_COMPARTMENT();
     192           0 :     c.check(t1);
     193             : }
     194             : 
     195             : template <class T1> inline void
     196           0 : assertSameCompartment(JSContext* cx, const T1& t1)
     197             : {
     198             : #ifdef JS_CRASH_DIAGNOSTICS
     199           0 :     START_ASSERT_SAME_COMPARTMENT();
     200           0 :     c.check(t1);
     201             : #endif
     202             : }
     203             : 
     204             : template <class T1> inline void
     205           0 : assertSameCompartmentDebugOnly(JSContext* cx, const T1& t1)
     206             : {
     207             : #if defined(DEBUG) && defined(JS_CRASH_DIAGNOSTICS)
     208           0 :     START_ASSERT_SAME_COMPARTMENT();
     209           0 :     c.check(t1);
     210             : #endif
     211             : }
     212             : 
     213             : template <class T1, class T2> inline void
     214           0 : assertSameCompartment(JSContext* cx, const T1& t1, const T2& t2)
     215             : {
     216             : #ifdef JS_CRASH_DIAGNOSTICS
     217           0 :     START_ASSERT_SAME_COMPARTMENT();
     218           0 :     c.check(t1);
     219           0 :     c.check(t2);
     220             : #endif
     221             : }
     222             : 
     223             : template <class T1, class T2, class T3> inline void
     224           0 : assertSameCompartment(JSContext* cx, const T1& t1, const T2& t2, const T3& t3)
     225             : {
     226             : #ifdef JS_CRASH_DIAGNOSTICS
     227           0 :     START_ASSERT_SAME_COMPARTMENT();
     228           0 :     c.check(t1);
     229           0 :     c.check(t2);
     230           0 :     c.check(t3);
     231             : #endif
     232             : }
     233             : 
     234             : template <class T1, class T2, class T3, class T4> inline void
     235           0 : assertSameCompartment(JSContext* cx,
     236             :                       const T1& t1, const T2& t2, const T3& t3, const T4& t4)
     237             : {
     238             : #ifdef JS_CRASH_DIAGNOSTICS
     239           0 :     START_ASSERT_SAME_COMPARTMENT();
     240           0 :     c.check(t1);
     241           0 :     c.check(t2);
     242           0 :     c.check(t3);
     243           0 :     c.check(t4);
     244             : #endif
     245             : }
     246             : 
     247             : template <class T1, class T2, class T3, class T4, class T5> inline void
     248             : assertSameCompartment(JSContext* cx,
     249             :                       const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5)
     250             : {
     251             : #ifdef JS_CRASH_DIAGNOSTICS
     252             :     START_ASSERT_SAME_COMPARTMENT();
     253             :     c.check(t1);
     254             :     c.check(t2);
     255             :     c.check(t3);
     256             :     c.check(t4);
     257             :     c.check(t5);
     258             : #endif
     259             : }
     260             : 
     261             : #undef START_ASSERT_SAME_COMPARTMENT
     262             : 
     263             : STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
     264             : MOZ_ALWAYS_INLINE bool
     265           0 : CallJSNative(JSContext* cx, Native native, const CallArgs& args)
     266             : {
     267           0 :     if (!CheckRecursionLimit(cx))
     268             :         return false;
     269             : 
     270             : #ifdef DEBUG
     271           0 :     bool alreadyThrowing = cx->isExceptionPending();
     272             : #endif
     273           0 :     assertSameCompartment(cx, args);
     274           0 :     bool ok = native(cx, args.length(), args.base());
     275           0 :     if (ok) {
     276           0 :         assertSameCompartment(cx, args.rval());
     277           0 :         MOZ_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
     278             :     }
     279             :     return ok;
     280             : }
     281             : 
     282             : STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
     283             : MOZ_ALWAYS_INLINE bool
     284           0 : CallNativeImpl(JSContext* cx, NativeImpl impl, const CallArgs& args)
     285             : {
     286             : #ifdef DEBUG
     287           0 :     bool alreadyThrowing = cx->isExceptionPending();
     288             : #endif
     289           0 :     assertSameCompartment(cx, args);
     290           0 :     bool ok = impl(cx, args);
     291           0 :     if (ok) {
     292           0 :         assertSameCompartment(cx, args.rval());
     293           0 :         MOZ_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
     294             :     }
     295           0 :     return ok;
     296             : }
     297             : 
     298             : STATIC_PRECONDITION(ubound(args.argv_) >= argc)
     299             : MOZ_ALWAYS_INLINE bool
     300           0 : CallJSNativeConstructor(JSContext* cx, Native native, const CallArgs& args)
     301             : {
     302             : #ifdef DEBUG
     303           0 :     RootedObject callee(cx, &args.callee());
     304             : #endif
     305             : 
     306           0 :     MOZ_ASSERT(args.thisv().isMagic());
     307           0 :     if (!CallJSNative(cx, native, args))
     308             :         return false;
     309             : 
     310             :     /*
     311             :      * Native constructors must return non-primitive values on success.
     312             :      * Although it is legal, if a constructor returns the callee, there is a
     313             :      * 99.9999% chance it is a bug. If any valid code actually wants the
     314             :      * constructor to return the callee, the assertion can be removed or
     315             :      * (another) conjunct can be added to the antecedent.
     316             :      *
     317             :      * Exceptions:
     318             :      *
     319             :      * - Proxies are exceptions to both rules: they can return primitives and
     320             :      *   they allow content to return the callee.
     321             :      *
     322             :      * - CallOrConstructBoundFunction is an exception as well because we might
     323             :      *   have used bind on a proxy function.
     324             :      *
     325             :      * - (new Object(Object)) returns the callee.
     326             :      */
     327           0 :     MOZ_ASSERT_IF(native != js::proxy_Construct &&
     328             :                   (!callee->is<JSFunction>() || callee->as<JSFunction>().native() != obj_construct),
     329             :                   args.rval().isObject() && callee != &args.rval().toObject());
     330             : 
     331             :     return true;
     332             : }
     333             : 
     334             : MOZ_ALWAYS_INLINE bool
     335           0 : CallJSGetterOp(JSContext* cx, GetterOp op, HandleObject obj, HandleId id,
     336             :                MutableHandleValue vp)
     337             : {
     338           0 :     if (!CheckRecursionLimit(cx))
     339             :         return false;
     340             : 
     341           0 :     assertSameCompartment(cx, obj, id, vp);
     342           0 :     bool ok = op(cx, obj, id, vp);
     343           0 :     if (ok)
     344           0 :         assertSameCompartment(cx, vp);
     345             :     return ok;
     346             : }
     347             : 
     348             : MOZ_ALWAYS_INLINE bool
     349           0 : CallJSSetterOp(JSContext* cx, SetterOp op, HandleObject obj, HandleId id, HandleValue v,
     350             :                ObjectOpResult& result)
     351             : {
     352           0 :     if (!CheckRecursionLimit(cx))
     353             :         return false;
     354             : 
     355           0 :     assertSameCompartment(cx, obj, id, v);
     356           0 :     return op(cx, obj, id, v, result);
     357             : }
     358             : 
     359             : inline bool
     360           0 : CallJSAddPropertyOp(JSContext* cx, JSAddPropertyOp op, HandleObject obj, HandleId id,
     361             :                     HandleValue v)
     362             : {
     363           0 :     if (!CheckRecursionLimit(cx))
     364             :         return false;
     365             : 
     366           0 :     assertSameCompartment(cx, obj, id, v);
     367           0 :     return op(cx, obj, id, v);
     368             : }
     369             : 
     370             : inline bool
     371           0 : CallJSDeletePropertyOp(JSContext* cx, JSDeletePropertyOp op, HandleObject receiver, HandleId id,
     372             :                        ObjectOpResult& result)
     373             : {
     374           0 :     if (!CheckRecursionLimit(cx))
     375             :         return false;
     376             : 
     377           0 :     assertSameCompartment(cx, receiver, id);
     378           0 :     if (op)
     379           0 :         return op(cx, receiver, id, result);
     380           0 :     return result.succeed();
     381             : }
     382             : 
     383             : MOZ_ALWAYS_INLINE bool
     384           0 : CheckForInterrupt(JSContext* cx)
     385             : {
     386           0 :     MOZ_ASSERT(!cx->isExceptionPending());
     387             :     // Add an inline fast-path since we have to check for interrupts in some hot
     388             :     // C++ loops of library builtins.
     389           0 :     if (MOZ_UNLIKELY(cx->hasAnyPendingInterrupt()))
     390           0 :         return cx->handleInterrupt();
     391             : 
     392           0 :     JS_INTERRUPT_POSSIBLY_FAIL();
     393             : 
     394             :     return true;
     395             : }
     396             : 
     397             : }  /* namespace js */
     398             : 
     399             : inline js::LifoAlloc&
     400             : JSContext::typeLifoAlloc()
     401             : {
     402           0 :     return zone()->types.typeLifoAlloc();
     403             : }
     404             : 
     405             : inline js::Nursery&
     406             : JSContext::nursery()
     407             : {
     408           0 :     return runtime()->gc.nursery();
     409             : }
     410             : 
     411             : inline void
     412           0 : JSContext::minorGC(JS::gcreason::Reason reason)
     413             : {
     414           0 :     runtime()->gc.minorGC(reason);
     415           0 : }
     416             : 
     417             : inline void
     418           0 : JSContext::setPendingException(const js::Value& v)
     419             : {
     420             : #if defined(NIGHTLY_BUILD)
     421             :     do {
     422             :         // Do not intercept exceptions if we are already
     423             :         // in the exception interceptor. That would lead
     424             :         // to infinite recursion.
     425           0 :         if (this->runtime()->errorInterception.isExecuting)
     426             :             break;
     427             : 
     428             :         // Check whether we have an interceptor at all.
     429           0 :         if (!this->runtime()->errorInterception.interceptor)
     430             :             break;
     431             : 
     432             :         // Make sure that we do not call the interceptor from within
     433             :         // the interceptor.
     434           0 :         this->runtime()->errorInterception.isExecuting = true;
     435             : 
     436             :         // The interceptor must be infallible.
     437           0 :         const mozilla::DebugOnly<bool> wasExceptionPending = this->isExceptionPending();
     438           0 :         this->runtime()->errorInterception.interceptor->interceptError(this, v);
     439           0 :         MOZ_ASSERT(wasExceptionPending == this->isExceptionPending());
     440             : 
     441           0 :         this->runtime()->errorInterception.isExecuting = false;
     442             :     } while (false);
     443             : #endif // defined(NIGHTLY_BUILD)
     444             : 
     445             :     // overRecursed_ is set after the fact by ReportOverRecursed.
     446           0 :     this->overRecursed_ = false;
     447           0 :     this->throwing = true;
     448           0 :     this->unwrappedException() = v;
     449             :     // We don't use assertSameCompartment here to allow
     450             :     // js::SetPendingExceptionCrossContext to work.
     451           0 :     MOZ_ASSERT_IF(v.isObject(), v.toObject().compartment() == compartment());
     452           0 : }
     453             : 
     454             : inline bool
     455           0 : JSContext::runningWithTrustedPrincipals()
     456             : {
     457           0 :     return !realm() || realm()->principals() == runtime()->trustedPrincipals();
     458             : }
     459             : 
     460             : inline void
     461           0 : JSContext::enterRealm(JS::Realm* realm)
     462             : {
     463             :     // We should never enter a realm while in the atoms zone.
     464           0 :     MOZ_ASSERT_IF(zone(), !zone()->isAtomsZone());
     465             : 
     466      123205 :     realm->enter();
     467           0 :     setRealm(realm);
     468      123205 : }
     469             : 
     470             : inline void
     471           0 : JSContext::enterAtomsZone(const js::AutoLockForExclusiveAccess& lock)
     472             : {
     473             :     // Only one thread can be in the atoms zone at a time.
     474           0 :     MOZ_ASSERT(runtime_->currentThreadHasExclusiveAccess());
     475             : 
     476       48526 :     realm_ = nullptr;
     477           0 :     zone_ = runtime_->atomsZone(lock);
     478       97052 :     arenas_ = &zone_->arenas;
     479           0 : }
     480             : 
     481             : template <typename T>
     482             : inline void
     483      115639 : JSContext::enterRealmOf(const T& target)
     484             : {
     485      231279 :     MOZ_ASSERT(JS::CellIsNotGray(target));
     486           0 :     enterRealm(target->realm());
     487      115640 : }
     488             : 
     489             : inline void
     490           0 : JSContext::enterNullRealm()
     491             : {
     492             :     // We should never enter a realm while in the atoms zone.
     493           0 :     MOZ_ASSERT_IF(zone(), !zone()->isAtomsZone());
     494             : 
     495        1127 :     setRealm(nullptr);
     496           0 : }
     497             : 
     498             : inline void
     499           0 : JSContext::leaveRealm(JS::Realm* oldRealm)
     500             : {
     501             :     // Only call leave() after we've setRealm()-ed away from the current realm.
     502           0 :     JS::Realm* startingRealm = realm_;
     503      124325 :     setRealm(oldRealm);
     504      124325 :     if (startingRealm)
     505           0 :         startingRealm->leave();
     506      124325 : }
     507             : 
     508             : inline void
     509             : JSContext::leaveAtomsZone(JS::Realm* oldRealm,
     510             :                           const js::AutoLockForExclusiveAccess& lock)
     511             : {
     512       48526 :     setRealm(oldRealm);
     513             : }
     514             : 
     515             : inline void
     516           0 : JSContext::setRealm(JS::Realm* realm)
     517             : {
     518             :     // Both the current and the new realm should be properly marked as
     519             :     // entered at this point.
     520      297172 :     MOZ_ASSERT_IF(realm_, realm_->hasBeenEnteredIgnoringJit());
     521      297172 :     MOZ_ASSERT_IF(realm, realm->hasBeenEnteredIgnoringJit());
     522             : 
     523             :     // This thread must have exclusive access to the zone.
     524      297172 :     MOZ_ASSERT_IF(realm, CurrentThreadCanAccessZone(realm->zone()));
     525             : 
     526      297171 :     realm_ = realm;
     527           0 :     zone_ = realm ? realm->zone() : nullptr;
     528      594346 :     arenas_ = zone_ ? &zone_->arenas : nullptr;
     529      297175 : }
     530             : 
     531             : inline JSScript*
     532           0 : JSContext::currentScript(jsbytecode** ppc,
     533             :                          MaybeAllowCrossCompartment allowCrossCompartment) const
     534             : {
     535           0 :     if (ppc)
     536       27811 :         *ppc = nullptr;
     537             : 
     538           0 :     js::Activation* act = activation();
     539           0 :     if (!act)
     540             :         return nullptr;
     541             : 
     542       33925 :     MOZ_ASSERT(act->cx() == this);
     543             : 
     544       67850 :     if (!allowCrossCompartment && act->compartment() != compartment())
     545             :         return nullptr;
     546             : 
     547           0 :     if (act->isJit()) {
     548        3626 :         if (act->hasWasmExitFP())
     549             :             return nullptr;
     550           0 :         JSScript* script = nullptr;
     551        3626 :         js::jit::GetPcScript(const_cast<JSContext*>(this), &script, ppc);
     552       10878 :         MOZ_ASSERT(allowCrossCompartment || script->compartment() == compartment());
     553           0 :         return script;
     554             :     }
     555             : 
     556       10245 :     MOZ_ASSERT(act->isInterpreter());
     557             : 
     558           0 :     js::InterpreterFrame* fp = act->asInterpreter()->current();
     559           0 :     MOZ_ASSERT(!fp->runningInJit());
     560             : 
     561           0 :     JSScript* script = fp->script();
     562           0 :     MOZ_ASSERT(allowCrossCompartment || script->compartment() == compartment());
     563             : 
     564           0 :     if (ppc) {
     565        4608 :         *ppc = act->asInterpreter()->regs().pc;
     566        4608 :         MOZ_ASSERT(script->containsPC(*ppc));
     567             :     }
     568             : 
     569             :     return script;
     570             : }
     571             : 
     572             : inline js::RuntimeCaches&
     573             : JSContext::caches()
     574             : {
     575           0 :     return runtime()->caches();
     576             : }
     577             : 
     578             : inline
     579        2442 : js::AutoKeepAtoms::AutoKeepAtoms(JSContext* cx
     580        2442 :                                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
     581        4884 :   : cx(cx)
     582             : {
     583        4884 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     584        4884 :     cx->zone()->keepAtoms();
     585        2442 : }
     586             : 
     587             : inline
     588             : js::AutoKeepAtoms::~AutoKeepAtoms()
     589             : {
     590             :     cx->zone()->releaseAtoms();
     591             : };
     592             : 
     593             : #endif /* vm_JSContext_inl_h */

Generated by: LCOV version 1.13-14-ga5dd952