LCOV - code coverage report
Current view: top level - js/src/vm - GeckoProfiler.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 82 284 28.9 %
Date: 2017-07-14 16:53:18 Functions: 15 31 48.4 %
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             : #include "vm/GeckoProfiler-inl.h"
       8             : 
       9             : #include "mozilla/DebugOnly.h"
      10             : 
      11             : #include "jsnum.h"
      12             : #include "jsprf.h"
      13             : #include "jsscript.h"
      14             : 
      15             : #include "jit/BaselineFrame.h"
      16             : #include "jit/BaselineJIT.h"
      17             : #include "jit/JitcodeMap.h"
      18             : #include "jit/JitFrameIterator.h"
      19             : #include "jit/JitFrames.h"
      20             : #include "vm/StringBuffer.h"
      21             : 
      22             : #include "jsgcinlines.h"
      23             : 
      24             : using namespace js;
      25             : 
      26             : using mozilla::DebugOnly;
      27             : 
      28           4 : GeckoProfiler::GeckoProfiler(JSRuntime* rt)
      29             :   : rt(rt),
      30             :     strings(mutexid::GeckoProfilerStrings),
      31             :     pseudoStack_(nullptr),
      32             :     slowAssertions(false),
      33             :     enabled_(false),
      34           4 :     eventMarker_(nullptr)
      35             : {
      36           4 :     MOZ_ASSERT(rt != nullptr);
      37           4 : }
      38             : 
      39             : bool
      40           4 : GeckoProfiler::init()
      41             : {
      42           8 :     auto locked = strings.lock();
      43           4 :     if (!locked->init())
      44           0 :         return false;
      45             : 
      46           4 :     return true;
      47             : }
      48             : 
      49             : void
      50           4 : GeckoProfiler::setProfilingStack(PseudoStack* pseudoStack)
      51             : {
      52           4 :     MOZ_ASSERT_IF(pseudoStack_, !enabled());
      53           4 :     MOZ_ASSERT(strings.lock()->initialized());
      54             : 
      55           4 :     pseudoStack_ = pseudoStack;
      56           4 : }
      57             : 
      58             : void
      59           0 : GeckoProfiler::setEventMarker(void (*fn)(const char*))
      60             : {
      61           0 :     eventMarker_ = fn;
      62           0 : }
      63             : 
      64             : /* Get a pointer to the top-most profiling frame, given the exit frame pointer. */
      65             : static void*
      66           0 : GetTopProfilingJitFrame(Activation* act)
      67             : {
      68           0 :     if (!act || !act->isJit())
      69           0 :         return nullptr;
      70             : 
      71             :     // For null exitFrame, there is no previous exit frame, just return.
      72           0 :     uint8_t* exitFP = act->asJit()->exitFP();
      73           0 :     if (!exitFP)
      74           0 :         return nullptr;
      75             : 
      76           0 :     jit::JitProfilingFrameIterator iter(exitFP);
      77           0 :     MOZ_ASSERT(!iter.done());
      78           0 :     return iter.fp();
      79             : }
      80             : 
      81             : bool
      82           0 : GeckoProfiler::enable(bool enabled)
      83             : {
      84           0 :     MOZ_ASSERT(installed());
      85             : 
      86           0 :     if (enabled_ == enabled)
      87           0 :         return true;
      88             : 
      89             :     // Execution in the runtime must be single threaded if the Gecko profiler
      90             :     // is enabled. There is only a single profiler stack in the runtime, from
      91             :     // which entries must be added/removed in a LIFO fashion.
      92           0 :     JSContext* cx = rt->activeContextFromOwnThread();
      93           0 :     if (enabled) {
      94           0 :         if (!rt->beginSingleThreadedExecution(cx))
      95           0 :             return false;
      96             :     } else {
      97           0 :         rt->endSingleThreadedExecution(cx);
      98             :     }
      99             : 
     100             :     /*
     101             :      * Ensure all future generated code will be instrumented, or that all
     102             :      * currently instrumented code is discarded
     103             :      */
     104           0 :     ReleaseAllJITCode(rt->defaultFreeOp());
     105             : 
     106             :     // This function is called when the Gecko profiler makes a new Sampler
     107             :     // (and thus, a new circular buffer). Set all current entries in the
     108             :     // JitcodeGlobalTable as expired and reset the buffer generation and lap
     109             :     // count.
     110           0 :     if (rt->hasJitRuntime() && rt->jitRuntime()->hasJitcodeGlobalTable())
     111           0 :         rt->jitRuntime()->getJitcodeGlobalTable()->setAllEntriesAsExpired(rt);
     112           0 :     rt->resetProfilerSampleBufferGen();
     113           0 :     rt->resetProfilerSampleBufferLapCount();
     114             : 
     115             :     // Ensure that lastProfilingFrame is null for all threads before 'enabled' becomes true.
     116           0 :     for (const CooperatingContext& target : rt->cooperatingContexts()) {
     117           0 :         if (target.context()->jitActivation) {
     118           0 :             target.context()->jitActivation->setLastProfilingFrame(nullptr);
     119           0 :             target.context()->jitActivation->setLastProfilingCallSite(nullptr);
     120             :         }
     121             :     }
     122             : 
     123           0 :     enabled_ = enabled;
     124             : 
     125             :     /* Toggle Gecko Profiler-related jumps on baseline jitcode.
     126             :      * The call to |ReleaseAllJITCode| above will release most baseline jitcode, but not
     127             :      * jitcode for scripts with active frames on the stack.  These scripts need to have
     128             :      * their profiler state toggled so they behave properly.
     129             :      */
     130           0 :     jit::ToggleBaselineProfiling(rt, enabled);
     131             : 
     132             :     /* Update lastProfilingFrame to point to the top-most JS jit-frame currently on
     133             :      * stack.
     134             :      */
     135           0 :     for (const CooperatingContext& target : rt->cooperatingContexts()) {
     136           0 :         if (target.context()->jitActivation) {
     137             :             // Walk through all activations, and set their lastProfilingFrame appropriately.
     138           0 :             if (enabled) {
     139           0 :                 Activation* act = target.context()->activation();
     140           0 :                 void* lastProfilingFrame = GetTopProfilingJitFrame(act);
     141             : 
     142           0 :                 jit::JitActivation* jitActivation = target.context()->jitActivation;
     143           0 :                 while (jitActivation) {
     144           0 :                     jitActivation->setLastProfilingFrame(lastProfilingFrame);
     145           0 :                     jitActivation->setLastProfilingCallSite(nullptr);
     146             : 
     147           0 :                     jitActivation = jitActivation->prevJitActivation();
     148           0 :                     lastProfilingFrame = GetTopProfilingJitFrame(jitActivation);
     149             :                 }
     150             :             } else {
     151           0 :                 jit::JitActivation* jitActivation = target.context()->jitActivation;
     152           0 :                 while (jitActivation) {
     153           0 :                     jitActivation->setLastProfilingFrame(nullptr);
     154           0 :                     jitActivation->setLastProfilingCallSite(nullptr);
     155           0 :                     jitActivation = jitActivation->prevJitActivation();
     156             :                 }
     157             :             }
     158             :         }
     159             :     }
     160             : 
     161             :     // WebAssembly code does not need to be released, but profiling string
     162             :     // labels have to be generated so that they are available during async
     163             :     // profiling stack iteration.
     164           0 :     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
     165           0 :         c->wasm.ensureProfilingLabels(enabled);
     166             : 
     167           0 :     return true;
     168             : }
     169             : 
     170             : /* Lookup the string for the function/script, creating one if necessary */
     171             : const char*
     172           0 : GeckoProfiler::profileString(JSScript* script, JSFunction* maybeFun)
     173             : {
     174           0 :     auto locked = strings.lock();
     175           0 :     MOZ_ASSERT(locked->initialized());
     176             : 
     177           0 :     ProfileStringMap::AddPtr s = locked->lookupForAdd(script);
     178             : 
     179           0 :     if (!s) {
     180           0 :         auto str = allocProfileString(script, maybeFun);
     181           0 :         if (!str || !locked->add(s, script, mozilla::Move(str)))
     182           0 :             return nullptr;
     183             :     }
     184             : 
     185           0 :     return s->value().get();
     186             : }
     187             : 
     188             : void
     189           0 : GeckoProfiler::onScriptFinalized(JSScript* script)
     190             : {
     191             :     /*
     192             :      * This function is called whenever a script is destroyed, regardless of
     193             :      * whether profiling has been turned on, so don't invoke a function on an
     194             :      * invalid hash set. Also, even if profiling was enabled but then turned
     195             :      * off, we still want to remove the string, so no check of enabled() is
     196             :      * done.
     197             :      */
     198           0 :     auto locked = strings.lock();
     199           0 :     if (!locked->initialized())
     200           0 :         return;
     201           0 :     if (ProfileStringMap::Ptr entry = locked->lookup(script))
     202           0 :         locked->remove(entry);
     203             : }
     204             : 
     205             : void
     206           0 : GeckoProfiler::markEvent(const char* event)
     207             : {
     208           0 :     MOZ_ASSERT(enabled());
     209           0 :     if (eventMarker_) {
     210           0 :         JS::AutoSuppressGCAnalysis nogc;
     211           0 :         eventMarker_(event);
     212             :     }
     213           0 : }
     214             : 
     215             : bool
     216           0 : GeckoProfiler::enter(JSContext* cx, JSScript* script, JSFunction* maybeFun)
     217             : {
     218           0 :     const char* dynamicString = profileString(script, maybeFun);
     219           0 :     if (dynamicString == nullptr) {
     220           0 :         ReportOutOfMemory(cx);
     221           0 :         return false;
     222             :     }
     223             : 
     224             : #ifdef DEBUG
     225             :     // In debug builds, assert the JS pseudo frames already on the stack
     226             :     // have a non-null pc. Only look at the top frames to avoid quadratic
     227             :     // behavior.
     228           0 :     uint32_t sp = pseudoStack_->stackPointer;
     229           0 :     if (sp > 0 && sp - 1 < PseudoStack::MaxEntries) {
     230           0 :         size_t start = (sp > 4) ? sp - 4 : 0;
     231           0 :         for (size_t i = start; i < sp - 1; i++)
     232           0 :             MOZ_ASSERT_IF(pseudoStack_->entries[i].isJs(), pseudoStack_->entries[i].pc());
     233             :     }
     234             : #endif
     235             : 
     236           0 :     pseudoStack_->pushJsFrame("", dynamicString, script, script->code());
     237           0 :     return true;
     238             : }
     239             : 
     240             : void
     241           0 : GeckoProfiler::exit(JSScript* script, JSFunction* maybeFun)
     242             : {
     243           0 :     pseudoStack_->pop();
     244             : 
     245             : #ifdef DEBUG
     246             :     /* Sanity check to make sure push/pop balanced */
     247           0 :     uint32_t sp = pseudoStack_->stackPointer;
     248           0 :     if (sp < PseudoStack::MaxEntries) {
     249           0 :         const char* dynamicString = profileString(script, maybeFun);
     250             :         /* Can't fail lookup because we should already be in the set */
     251           0 :         MOZ_ASSERT(dynamicString);
     252             : 
     253             :         // Bug 822041
     254           0 :         if (!pseudoStack_->entries[sp].isJs()) {
     255           0 :             fprintf(stderr, "--- ABOUT TO FAIL ASSERTION ---\n");
     256           0 :             fprintf(stderr, " entries=%p size=%u/%u\n",
     257           0 :                             (void*) pseudoStack_->entries,
     258           0 :                             uint32_t(pseudoStack_->stackPointer),
     259           0 :                             PseudoStack::MaxEntries);
     260           0 :             for (int32_t i = sp; i >= 0; i--) {
     261           0 :                 ProfileEntry& entry = pseudoStack_->entries[i];
     262           0 :                 if (entry.isJs())
     263           0 :                     fprintf(stderr, "  [%d] JS %s\n", i, entry.dynamicString());
     264             :                 else
     265           0 :                     fprintf(stderr, "  [%d] C line %d %s\n", i, entry.line(), entry.dynamicString());
     266             :             }
     267             :         }
     268             : 
     269           0 :         ProfileEntry& entry = pseudoStack_->entries[sp];
     270           0 :         MOZ_ASSERT(entry.isJs());
     271           0 :         MOZ_ASSERT(entry.script() == script);
     272           0 :         MOZ_ASSERT(strcmp((const char*) entry.dynamicString(), dynamicString) == 0);
     273             :     }
     274             : #endif
     275           0 : }
     276             : 
     277             : /*
     278             :  * Serializes the script/function pair into a "descriptive string" which is
     279             :  * allowed to fail. This function cannot trigger a GC because it could finalize
     280             :  * some scripts, resize the hash table of profile strings, and invalidate the
     281             :  * AddPtr held while invoking allocProfileString.
     282             :  */
     283             : UniqueChars
     284           0 : GeckoProfiler::allocProfileString(JSScript* script, JSFunction* maybeFun)
     285             : {
     286             :     // Note: this profiler string is regexp-matched by
     287             :     // devtools/client/profiler/cleopatra/js/parserWorker.js.
     288             : 
     289             :     // Get the function name, if any.
     290           0 :     JSAtom* atom = maybeFun ? maybeFun->displayAtom() : nullptr;
     291             : 
     292             :     // Get the script filename, if any, and its length.
     293           0 :     const char* filename = script->filename();
     294           0 :     if (filename == nullptr)
     295           0 :         filename = "<unknown>";
     296           0 :     size_t lenFilename = strlen(filename);
     297             : 
     298             :     // Get the line number and its length as a string.
     299           0 :     uint64_t lineno = script->lineno();
     300           0 :     size_t lenLineno = 1;
     301           0 :     for (uint64_t i = lineno; i /= 10; lenLineno++);
     302             : 
     303             :     // Determine the required buffer size.
     304           0 :     size_t len = lenFilename + lenLineno + 1; // +1 for the ":" separating them.
     305           0 :     if (atom) {
     306           0 :         len += JS::GetDeflatedUTF8StringLength(atom) + 3; // +3 for the " (" and ")" it adds.
     307             :     }
     308             : 
     309             :     // Allocate the buffer.
     310           0 :     UniqueChars cstr(js_pod_malloc<char>(len + 1));
     311           0 :     if (!cstr)
     312           0 :         return nullptr;
     313             : 
     314             :     // Construct the descriptive string.
     315           0 :     DebugOnly<size_t> ret;
     316           0 :     if (atom) {
     317           0 :         UniqueChars atomStr = StringToNewUTF8CharsZ(nullptr, *atom);
     318           0 :         if (!atomStr)
     319           0 :             return nullptr;
     320             : 
     321           0 :         ret = snprintf(cstr.get(), len + 1, "%s (%s:%" PRIu64 ")", atomStr.get(), filename, lineno);
     322             :     } else {
     323           0 :         ret = snprintf(cstr.get(), len + 1, "%s:%" PRIu64, filename, lineno);
     324             :     }
     325             : 
     326           0 :     MOZ_ASSERT(ret == len, "Computed length should match actual length!");
     327             : 
     328           0 :     return cstr;
     329             : }
     330             : 
     331             : void
     332          22 : GeckoProfiler::trace(JSTracer* trc)
     333             : {
     334          22 :     if (pseudoStack_) {
     335          22 :         size_t size = pseudoStack_->stackSize();
     336         307 :         for (size_t i = 0; i < size; i++)
     337         285 :             pseudoStack_->entries[i].trace(trc);
     338             :     }
     339          22 : }
     340             : 
     341             : void
     342           0 : GeckoProfiler::fixupStringsMapAfterMovingGC()
     343             : {
     344           0 :     auto locked = strings.lock();
     345           0 :     if (!locked->initialized())
     346           0 :         return;
     347             : 
     348           0 :     for (ProfileStringMap::Enum e(locked.get()); !e.empty(); e.popFront()) {
     349           0 :         JSScript* script = e.front().key();
     350           0 :         if (IsForwarded(script)) {
     351           0 :             script = Forwarded(script);
     352           0 :             e.rekeyFront(script);
     353             :         }
     354             :     }
     355             : }
     356             : 
     357             : #ifdef JSGC_HASH_TABLE_CHECKS
     358             : void
     359           0 : GeckoProfiler::checkStringsMapAfterMovingGC()
     360             : {
     361           0 :     auto locked = strings.lock();
     362           0 :     if (!locked->initialized())
     363           0 :         return;
     364             : 
     365           0 :     for (auto r = locked->all(); !r.empty(); r.popFront()) {
     366           0 :         JSScript* script = r.front().key();
     367           0 :         CheckGCThingAfterMovingGC(script);
     368           0 :         auto ptr = locked->lookup(script);
     369           0 :         MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
     370             :     }
     371             : }
     372             : #endif
     373             : 
     374             : void
     375         285 : ProfileEntry::trace(JSTracer* trc)
     376             : {
     377         285 :     if (isJs()) {
     378         101 :         JSScript* s = rawScript();
     379         101 :         TraceNullableRoot(trc, &s, "ProfileEntry script");
     380         101 :         spOrScript = s;
     381             :     }
     382         285 : }
     383             : 
     384       17386 : GeckoProfilerEntryMarker::GeckoProfilerEntryMarker(JSRuntime* rt,
     385             :                                                    JSScript* script
     386       17386 :                                                    MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
     387       17386 :     : profiler(&rt->geckoProfiler())
     388             : {
     389       17386 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     390       17386 :     if (!profiler->installed()) {
     391           0 :         profiler = nullptr;
     392           0 :         return;
     393             :     }
     394       17386 :     spBefore_ = profiler->stackPointer();
     395             : 
     396             :     // We want to push a CPP frame so the profiler can correctly order JS and native stacks.
     397             :     // Only the sp value is important.
     398       17386 :     profiler->pseudoStack_->pushCppFrame(
     399             :         /* label = */ "", /* dynamicString = */ nullptr, /* sp = */ this, /* line = */ 0,
     400       17386 :         ProfileEntry::Kind::CPP_MARKER_FOR_JS, ProfileEntry::Category::OTHER);
     401             : 
     402       17386 :     profiler->pseudoStack_->pushJsFrame(
     403       17386 :         "js::RunScript", /* dynamicString = */ nullptr, script, script->code());
     404             : }
     405             : 
     406       34758 : GeckoProfilerEntryMarker::~GeckoProfilerEntryMarker()
     407             : {
     408       17379 :     if (profiler == nullptr)
     409           0 :         return;
     410             : 
     411       17379 :     profiler->pseudoStack_->pop();    // the JS frame
     412       17379 :     profiler->pseudoStack_->pop();    // the BEGIN_PSEUDO_JS frame
     413       17379 :     MOZ_ASSERT(spBefore_ == profiler->stackPointer());
     414       17379 : }
     415             : 
     416        6488 : AutoGeckoProfilerEntry::AutoGeckoProfilerEntry(JSRuntime* rt, const char* label,
     417             :                                                ProfileEntry::Category category
     418        6488 :                                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
     419        6488 :     : profiler_(&rt->geckoProfiler())
     420             : {
     421        6488 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     422        6488 :     if (!profiler_->installed()) {
     423           0 :         profiler_ = nullptr;
     424           0 :         return;
     425             :     }
     426        6488 :     spBefore_ = profiler_->stackPointer();
     427             : 
     428        6488 :     profiler_->pseudoStack_->pushCppFrame(
     429             :         label, /* dynamicString = */ nullptr, /* sp = */ this, /* line = */ 0,
     430        6488 :         ProfileEntry::Kind::CPP_NORMAL, category);
     431             : }
     432             : 
     433       12976 : AutoGeckoProfilerEntry::~AutoGeckoProfilerEntry()
     434             : {
     435        6488 :     if (!profiler_)
     436           0 :         return;
     437             : 
     438        6488 :     profiler_->pseudoStack_->pop();
     439        6488 :     MOZ_ASSERT(spBefore_ == profiler_->stackPointer());
     440        6488 : }
     441             : 
     442         141 : GeckoProfilerBaselineOSRMarker::GeckoProfilerBaselineOSRMarker(JSRuntime* rt, bool hasProfilerFrame
     443         141 :                                                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
     444         141 :     : profiler(&rt->geckoProfiler())
     445             : {
     446         141 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     447         141 :     if (!hasProfilerFrame || !profiler->enabled()) {
     448         141 :         profiler = nullptr;
     449         282 :         return;
     450             :     }
     451             : 
     452           0 :     uint32_t sp = profiler->pseudoStack_->stackPointer;
     453           0 :     if (sp >= PseudoStack::MaxEntries) {
     454           0 :         profiler = nullptr;
     455           0 :         return;
     456             :     }
     457             : 
     458           0 :     spBefore_ = sp;
     459           0 :     if (sp == 0)
     460           0 :         return;
     461             : 
     462           0 :     ProfileEntry& entry = profiler->pseudoStack_->entries[sp - 1];
     463           0 :     MOZ_ASSERT(entry.kind() == ProfileEntry::Kind::JS_NORMAL);
     464           0 :     entry.setKind(ProfileEntry::Kind::JS_OSR);
     465             : }
     466             : 
     467         282 : GeckoProfilerBaselineOSRMarker::~GeckoProfilerBaselineOSRMarker()
     468             : {
     469         141 :     if (profiler == nullptr)
     470         141 :         return;
     471             : 
     472           0 :     uint32_t sp = profiler->stackPointer();
     473           0 :     MOZ_ASSERT(spBefore_ == sp);
     474           0 :     if (sp == 0)
     475           0 :         return;
     476             : 
     477           0 :     ProfileEntry& entry = profiler->stack()[sp - 1];
     478           0 :     MOZ_ASSERT(entry.kind() == ProfileEntry::Kind::JS_OSR);
     479           0 :     entry.setKind(ProfileEntry::Kind::JS_NORMAL);
     480         141 : }
     481             : 
     482             : JS_PUBLIC_API(JSScript*)
     483           0 : ProfileEntry::script() const
     484             : {
     485           0 :     MOZ_ASSERT(isJs());
     486           0 :     auto script = reinterpret_cast<JSScript*>(spOrScript);
     487           0 :     if (!script)
     488           0 :         return nullptr;
     489             : 
     490             :     // If profiling is supressed then we can't trust the script pointers to be
     491             :     // valid as they could be in the process of being moved by a compacting GC
     492             :     // (although it's still OK to get the runtime from them).
     493             :     //
     494             :     // We only need to check the active context here, as
     495             :     // AutoSuppressProfilerSampling prohibits the runtime's active context from
     496             :     // being changed while it exists.
     497           0 :     JSContext* cx = script->runtimeFromAnyThread()->activeContext();
     498           0 :     if (!cx->isProfilerSamplingEnabled())
     499           0 :         return nullptr;
     500             : 
     501           0 :     MOZ_ASSERT(!IsForwarded(script));
     502           0 :     return script;
     503             : }
     504             : 
     505             : JS_FRIEND_API(jsbytecode*)
     506           0 : ProfileEntry::pc() const
     507             : {
     508           0 :     MOZ_ASSERT(isJs());
     509           0 :     if (lineOrPcOffset == NullPCOffset)
     510           0 :         return nullptr;
     511             : 
     512           0 :     JSScript* script = this->script();
     513           0 :     return script ? script->offsetToPC(lineOrPcOffset) : nullptr;
     514             : }
     515             : 
     516             : /* static */ int32_t
     517       17386 : ProfileEntry::pcToOffset(JSScript* aScript, jsbytecode* aPc) {
     518       17386 :     return aPc ? aScript->pcToOffset(aPc) : NullPCOffset;
     519             : }
     520             : 
     521             : void
     522           0 : ProfileEntry::setPC(jsbytecode* pc)
     523             : {
     524           0 :     MOZ_ASSERT(isJs());
     525           0 :     JSScript* script = this->script();
     526           0 :     MOZ_ASSERT(script); // This should not be called while profiling is suppressed.
     527           0 :     lineOrPcOffset = pcToOffset(script, pc);
     528           0 : }
     529             : 
     530             : JS_FRIEND_API(void)
     531           4 : js::SetContextProfilingStack(JSContext* cx, PseudoStack* pseudoStack)
     532             : {
     533           4 :     cx->runtime()->geckoProfiler().setProfilingStack(pseudoStack);
     534           4 : }
     535             : 
     536             : JS_FRIEND_API(void)
     537           0 : js::EnableContextProfilingStack(JSContext* cx, bool enabled)
     538             : {
     539           0 :     if (!cx->runtime()->geckoProfiler().enable(enabled))
     540           0 :         MOZ_CRASH("Execution in this runtime should already be single threaded");
     541           0 : }
     542             : 
     543             : JS_FRIEND_API(void)
     544           0 : js::RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*))
     545             : {
     546           0 :     MOZ_ASSERT(cx->runtime()->geckoProfiler().enabled());
     547           0 :     cx->runtime()->geckoProfiler().setEventMarker(fn);
     548           0 : }
     549             : 
     550         632 : AutoSuppressProfilerSampling::AutoSuppressProfilerSampling(JSContext* cx
     551         632 :                                                            MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
     552             :   : cx_(cx),
     553         632 :     previouslyEnabled_(cx->isProfilerSamplingEnabled()),
     554        1264 :     prohibitContextChange_(cx->runtime())
     555             : {
     556         632 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     557         632 :     if (previouslyEnabled_)
     558         632 :         cx_->disableProfilerSampling();
     559         632 : }
     560             : 
     561        1264 : AutoSuppressProfilerSampling::~AutoSuppressProfilerSampling()
     562             : {
     563         632 :     if (previouslyEnabled_)
     564         632 :         cx_->enableProfilerSampling();
     565         632 : }

Generated by: LCOV version 1.13