LCOV - code coverage report
Current view: top level - js/src/vm - TraceLogging.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 103 566 18.2 %
Date: 2017-07-14 16:53:18 Functions: 18 52 34.6 %
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/TraceLogging.h"
       8             : 
       9             : #include "mozilla/DebugOnly.h"
      10             : #include "mozilla/MemoryReporting.h"
      11             : #include "mozilla/ScopeExit.h"
      12             : 
      13             : #include <string.h>
      14             : 
      15             : #include "jsapi.h"
      16             : #include "jsprf.h"
      17             : #include "jsscript.h"
      18             : 
      19             : #include "jit/BaselineJIT.h"
      20             : #include "jit/CompileWrappers.h"
      21             : #include "threading/LockGuard.h"
      22             : #include "vm/Runtime.h"
      23             : #include "vm/Time.h"
      24             : #include "vm/TraceLoggingGraph.h"
      25             : 
      26             : #include "jit/JitFrames-inl.h"
      27             : 
      28             : using namespace js;
      29             : using namespace js::jit;
      30             : 
      31             : using mozilla::DebugOnly;
      32             : using mozilla::NativeEndian;
      33             : 
      34             : TraceLoggerThreadState* traceLoggerState = nullptr;
      35             : 
      36             : #if defined(MOZ_HAVE_RDTSC)
      37             : 
      38           3 : uint64_t inline rdtsc() {
      39           3 :     return ReadTimestampCounter();
      40             : }
      41             : 
      42             : #elif defined(__powerpc__)
      43             : static __inline__ uint64_t
      44             : rdtsc(void)
      45             : {
      46             :     uint64_t result=0;
      47             :     uint32_t upper, lower,tmp;
      48             :     __asm__ volatile(
      49             :             "0:                  \n"
      50             :             "\tmftbu   %0           \n"
      51             :             "\tmftb    %1           \n"
      52             :             "\tmftbu   %2           \n"
      53             :             "\tcmpw    %2,%0        \n"
      54             :             "\tbne     0b         \n"
      55             :             : "=r"(upper),"=r"(lower),"=r"(tmp)
      56             :             );
      57             :     result = upper;
      58             :     result = result<<32;
      59             :     result = result|lower;
      60             : 
      61             :     return result;
      62             : 
      63             : }
      64             : #elif defined(__arm__) || defined(__aarch64__)
      65             : 
      66             : #include <sys/time.h>
      67             : 
      68             : static __inline__ uint64_t
      69             : rdtsc(void)
      70             : {
      71             :     struct timeval tv;
      72             :     gettimeofday(&tv, NULL);
      73             :     uint64_t ret = tv.tv_sec;
      74             :     ret *= 1000000;
      75             :     ret += tv.tv_usec;
      76             :     return ret;
      77             : }
      78             : 
      79             : #else
      80             : 
      81             : static __inline__ uint64_t
      82             : rdtsc(void)
      83             : {
      84             :     return 0;
      85             : }
      86             : 
      87             : #endif // defined(MOZ_HAVE_RDTSC)
      88             : 
      89             : static bool
      90       48057 : EnsureTraceLoggerState()
      91             : {
      92       48057 :     if (MOZ_LIKELY(traceLoggerState))
      93       48054 :         return true;
      94             : 
      95           3 :     traceLoggerState = js_new<TraceLoggerThreadState>();
      96           3 :     if (!traceLoggerState)
      97           0 :         return false;
      98             : 
      99           3 :     if (!traceLoggerState->init()) {
     100           0 :         DestroyTraceLoggerThreadState();
     101           0 :         return false;
     102             :     }
     103             : 
     104           3 :     return true;
     105             : }
     106             : 
     107             : size_t
     108           0 : js::SizeOfTraceLogState(mozilla::MallocSizeOf mallocSizeOf)
     109             : {
     110           0 :     return traceLoggerState ? traceLoggerState->sizeOfIncludingThis(mallocSizeOf) : 0;
     111             : }
     112             : 
     113             : void
     114           0 : js::DestroyTraceLoggerThreadState()
     115             : {
     116           0 :     if (traceLoggerState) {
     117           0 :         js_delete(traceLoggerState);
     118           0 :         traceLoggerState = nullptr;
     119             :     }
     120           0 : }
     121             : 
     122             : #ifdef DEBUG
     123             : bool
     124           0 : js::CurrentThreadOwnsTraceLoggerThreadStateLock()
     125             : {
     126           0 :     return traceLoggerState && traceLoggerState->lock.ownedByCurrentThread();
     127             : }
     128             : #endif
     129             : 
     130             : void
     131           0 : js::DestroyTraceLogger(TraceLoggerThread* logger)
     132             : {
     133           0 :     if (!EnsureTraceLoggerState())
     134           0 :         return;
     135           0 :     traceLoggerState->destroyLogger(logger);
     136             : }
     137             : 
     138             : bool
     139          22 : TraceLoggerThread::init()
     140             : {
     141          22 :     if (!events.init())
     142           0 :         return false;
     143             : 
     144             :     // Minimum amount of capacity needed for operation to allow flushing.
     145             :     // Flushing requires space for the actual event and two spaces to log the
     146             :     // start and stop of flushing.
     147          22 :     if (!events.ensureSpaceBeforeAdd(3))
     148           0 :         return false;
     149             : 
     150          22 :     return true;
     151             : }
     152             : 
     153             : void
     154           0 : TraceLoggerThread::initGraph()
     155             : {
     156             :     // Create a graph. I don't like this is called reset, but it locks the
     157             :     // graph into the UniquePtr. So it gets deleted when TraceLoggerThread
     158             :     // is destructed.
     159           0 :     graph.reset(js_new<TraceLoggerGraph>());
     160           0 :     if (!graph.get())
     161           0 :         return;
     162             : 
     163           0 :     MOZ_ASSERT(traceLoggerState);
     164           0 :     uint64_t start = rdtsc() - traceLoggerState->startupTime;
     165           0 :     if (!graph->init(start)) {
     166           0 :         graph = nullptr;
     167           0 :         return;
     168             :     }
     169             : 
     170             :     // Report the textIds to the graph.
     171           0 :     for (uint32_t i = 0; i < TraceLogger_LastTreeItem; i++) {
     172           0 :         TraceLoggerTextId id = TraceLoggerTextId(i);
     173           0 :         graph->addTextId(i, TLTextIdString(id));
     174             :     }
     175           0 :     graph->addTextId(TraceLogger_LastTreeItem, "TraceLogger internal");
     176           0 :     for (uint32_t i = TraceLogger_LastTreeItem + 1; i < TraceLogger_Last; i++) {
     177           0 :         TraceLoggerTextId id = TraceLoggerTextId(i);
     178           0 :         graph->addTextId(i, TLTextIdString(id));
     179             :     }
     180             : }
     181             : 
     182           0 : TraceLoggerThread::~TraceLoggerThread()
     183             : {
     184           0 :     if (graph.get()) {
     185           0 :         if (!failed)
     186           0 :             graph->log(events);
     187           0 :         graph = nullptr;
     188             :     }
     189           0 : }
     190             : 
     191             : bool
     192           0 : TraceLoggerThread::enable()
     193             : {
     194           0 :     if (enabled_ > 0) {
     195           0 :         enabled_++;
     196           0 :         return true;
     197             :     }
     198             : 
     199           0 :     if (failed)
     200           0 :         return false;
     201             : 
     202           0 :     enabled_ = 1;
     203           0 :     logTimestamp(TraceLogger_Enable);
     204             : 
     205           0 :     return true;
     206             : }
     207             : 
     208             : bool
     209           0 : TraceLoggerThread::fail(JSContext* cx, const char* error)
     210             : {
     211           0 :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TRACELOGGER_ENABLE_FAIL, error);
     212           0 :     failed = true;
     213           0 :     enabled_ = 0;
     214             : 
     215           0 :     return false;
     216             : }
     217             : 
     218             : void
     219           0 : TraceLoggerThread::silentFail(const char* error)
     220             : {
     221           0 :     traceLoggerState->maybeSpewError(error);
     222           0 :     failed = true;
     223           0 :     enabled_ = 0;
     224           0 : }
     225             : 
     226             : size_t
     227           0 : TraceLoggerThread::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
     228             : {
     229           0 :     size_t size = 0;
     230             : #ifdef DEBUG
     231           0 :     size += graphStack.sizeOfExcludingThis(mallocSizeOf);
     232             : #endif
     233           0 :     size += events.sizeOfExcludingThis(mallocSizeOf);
     234           0 :     if (graph.get())
     235           0 :         size += graph->sizeOfIncludingThis(mallocSizeOf);
     236           0 :     return size;
     237             : }
     238             : 
     239             : size_t
     240           0 : TraceLoggerThread::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
     241             : {
     242           0 :     return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
     243             : }
     244             : 
     245             : bool
     246           0 : TraceLoggerThread::enable(JSContext* cx)
     247             : {
     248           0 :     if (!enable())
     249           0 :         return fail(cx, "internal error");
     250             : 
     251           0 :     if (enabled_ == 1) {
     252             :         // Get the top Activation to log the top script/pc (No inlined frames).
     253           0 :         ActivationIterator iter(cx);
     254           0 :         Activation* act = iter.activation();
     255             : 
     256           0 :         if (!act)
     257           0 :             return fail(cx, "internal error");
     258             : 
     259           0 :         JSScript* script = nullptr;
     260           0 :         int32_t engine = 0;
     261             : 
     262           0 :         if (act->isJit()) {
     263           0 :             JitFrameIterator it(iter);
     264             : 
     265           0 :             while (!it.isScripted() && !it.done())
     266           0 :                 ++it;
     267             : 
     268           0 :             MOZ_ASSERT(!it.done());
     269           0 :             MOZ_ASSERT(it.isIonJS() || it.isBaselineJS());
     270             : 
     271           0 :             script = it.script();
     272           0 :             engine = it.isIonJS() ? TraceLogger_IonMonkey : TraceLogger_Baseline;
     273           0 :         } else if (act->isWasm()) {
     274             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TRACELOGGER_ENABLE_FAIL,
     275           0 :                                       "not yet supported in wasm code");
     276           0 :             return false;
     277             :         } else {
     278           0 :             MOZ_ASSERT(act->isInterpreter());
     279           0 :             InterpreterFrame* fp = act->asInterpreter()->current();
     280           0 :             MOZ_ASSERT(!fp->runningInJit());
     281             : 
     282           0 :             script = fp->script();
     283           0 :             engine = TraceLogger_Interpreter;
     284             :         }
     285           0 :         if (script->compartment() != cx->compartment())
     286           0 :             return fail(cx, "compartment mismatch");
     287             : 
     288           0 :         TraceLoggerEvent event(TraceLogger_Scripts, script);
     289           0 :         startEvent(event);
     290           0 :         startEvent(engine);
     291             :     }
     292             : 
     293           0 :     return true;
     294             : }
     295             : 
     296             : bool
     297           0 : TraceLoggerThread::disable(bool force, const char* error)
     298             : {
     299           0 :     if (failed) {
     300           0 :         MOZ_ASSERT(enabled_ == 0);
     301           0 :         return false;
     302             :     }
     303             : 
     304           0 :     if (enabled_ == 0)
     305           0 :         return true;
     306             : 
     307           0 :     if (enabled_ > 1 && !force) {
     308           0 :         enabled_--;
     309           0 :         return true;
     310             :     }
     311             : 
     312           0 :     if (force)
     313           0 :         traceLoggerState->maybeSpewError(error);
     314             : 
     315           0 :     logTimestamp(TraceLogger_Disable);
     316           0 :     enabled_ = 0;
     317             : 
     318           0 :     return true;
     319             : }
     320             : 
     321             : const char*
     322           0 : TraceLoggerThread::maybeEventText(uint32_t id)
     323             : {
     324           0 :     if (id < TraceLogger_Last)
     325           0 :         return TLTextIdString(static_cast<TraceLoggerTextId>(id));
     326           0 :     return traceLoggerState->maybeEventText(id);
     327             : }
     328             : 
     329             : const char*
     330           0 : TraceLoggerThreadState::maybeEventText(uint32_t id)
     331             : {
     332           0 :     LockGuard<Mutex> guard(lock);
     333             : 
     334           0 :     TextIdHashMap::Ptr p = textIdPayloads.lookup(id);
     335           0 :     if (!p)
     336           0 :         return nullptr;
     337             : 
     338           0 :     return p->value()->string();
     339             : }
     340             : 
     341             : size_t
     342           0 : TraceLoggerThreadState::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
     343             : {
     344           0 :     LockGuard<Mutex> guard(lock);
     345             : 
     346             :     // Do not count threadLoggers since they are counted by JSContext::traceLogger.
     347             : 
     348           0 :     size_t size = 0;
     349           0 :     size += pointerMap.sizeOfExcludingThis(mallocSizeOf);
     350           0 :     if (textIdPayloads.initialized()) {
     351           0 :         size += textIdPayloads.sizeOfExcludingThis(mallocSizeOf);
     352           0 :         for (TextIdHashMap::Range r = textIdPayloads.all(); !r.empty(); r.popFront())
     353           0 :             r.front().value()->sizeOfIncludingThis(mallocSizeOf);
     354             :     }
     355           0 :     return size;
     356             : }
     357             : 
     358             : bool
     359           0 : TraceLoggerThread::textIdIsScriptEvent(uint32_t id)
     360             : {
     361           0 :     if (id < TraceLogger_Last)
     362           0 :         return false;
     363             : 
     364             :     // Currently this works by checking if text begins with "script".
     365           0 :     const char* str = eventText(id);
     366           0 :     return EqualChars(str, "script", 6);
     367             : }
     368             : 
     369             : void
     370           0 : TraceLoggerThread::extractScriptDetails(uint32_t textId, const char** filename, size_t* filename_len,
     371             :                                         const char** lineno, size_t* lineno_len, const char** colno,
     372             :                                         size_t* colno_len)
     373             : {
     374           0 :     MOZ_ASSERT(textIdIsScriptEvent(textId));
     375             : 
     376           0 :     const char* script = eventText(textId);
     377             : 
     378             :     // Get the start of filename (remove 'script ' at the start).
     379           0 :     MOZ_ASSERT(EqualChars(script, "script ", 7));
     380           0 :     *filename = script + 7;
     381             : 
     382             :     // Get the start of lineno and colno.
     383           0 :     *lineno = script;
     384           0 :     *colno = script;
     385           0 :     const char* next = script - 1;
     386           0 :     while ((next = strchr(next + 1, ':'))) {
     387           0 :         *lineno = *colno;
     388           0 :         *colno = next;
     389             :     }
     390             : 
     391           0 :     MOZ_ASSERT(*lineno && *lineno != script);
     392           0 :     MOZ_ASSERT(*colno && *colno != script);
     393             : 
     394             :     // Remove the ':' at the front.
     395           0 :     *lineno = *lineno + 1;
     396           0 :     *colno = *colno + 1;
     397             : 
     398           0 :     *filename_len = *lineno - *filename - 1;
     399           0 :     *lineno_len = *colno - *lineno - 1;
     400           0 :     *colno_len = strlen(*colno);
     401           0 : }
     402             : 
     403             : TraceLoggerEventPayload*
     404           0 : TraceLoggerThreadState::getOrCreateEventPayload(const char* text)
     405             : {
     406           0 :     LockGuard<Mutex> guard(lock);
     407             : 
     408           0 :     PointerHashMap::AddPtr p = pointerMap.lookupForAdd((const void*)text);
     409           0 :     if (p) {
     410           0 :         MOZ_ASSERT(p->value()->textId() < nextTextId); // Sanity check.
     411           0 :         p->value()->use();
     412           0 :         return p->value();
     413             :     }
     414             : 
     415           0 :     char* str = js_strdup(text);
     416           0 :     if (!str)
     417           0 :         return nullptr;
     418             : 
     419           0 :     uint32_t textId = nextTextId;
     420             : 
     421           0 :     TraceLoggerEventPayload* payload = js_new<TraceLoggerEventPayload>(textId, str);
     422           0 :     if (!payload) {
     423           0 :         js_free(str);
     424           0 :         return nullptr;
     425             :     }
     426             : 
     427           0 :     if (!textIdPayloads.putNew(textId, payload)) {
     428           0 :         js_delete(payload);
     429           0 :         payload = nullptr;
     430           0 :         return nullptr;
     431             :     }
     432             : 
     433           0 :     payload->use();
     434             : 
     435           0 :     nextTextId++;
     436             : 
     437           0 :     if (!pointerMap.add(p, text, payload))
     438           0 :         return nullptr;
     439             : 
     440           0 :     payload->incPointerCount();
     441             : 
     442           0 :     return payload;
     443             : }
     444             : 
     445             : TraceLoggerEventPayload*
     446           0 : TraceLoggerThreadState::getOrCreateEventPayload(const char* filename,
     447             :                                                 size_t lineno, size_t colno, const void* ptr)
     448             : {
     449           0 :     if (!filename)
     450           0 :         filename = "<unknown>";
     451             : 
     452           0 :     LockGuard<Mutex> guard(lock);
     453             : 
     454           0 :     PointerHashMap::AddPtr p;
     455           0 :     if (ptr) {
     456           0 :         p = pointerMap.lookupForAdd(ptr);
     457           0 :         if (p) {
     458           0 :             MOZ_ASSERT(p->value()->textId() < nextTextId); // Sanity check.
     459           0 :             p->value()->use();
     460           0 :             return p->value();
     461             :         }
     462             :     }
     463             : 
     464             :     // Compute the length of the string to create.
     465           0 :     size_t lenFilename = strlen(filename);
     466           0 :     size_t lenLineno = 1;
     467           0 :     for (size_t i = lineno; i /= 10; lenLineno++);
     468           0 :     size_t lenColno = 1;
     469           0 :     for (size_t i = colno; i /= 10; lenColno++);
     470             : 
     471           0 :     size_t len = 7 + lenFilename + 1 + lenLineno + 1 + lenColno;
     472           0 :     char* str = js_pod_malloc<char>(len + 1);
     473           0 :     if (!str)
     474           0 :         return nullptr;
     475             : 
     476             :     DebugOnly<size_t> ret =
     477           0 :         snprintf(str, len + 1, "script %s:%" PRIuSIZE ":%" PRIuSIZE, filename, lineno, colno);
     478           0 :     MOZ_ASSERT(ret == len);
     479           0 :     MOZ_ASSERT(strlen(str) == len);
     480             : 
     481           0 :     uint32_t textId = nextTextId;
     482           0 :     TraceLoggerEventPayload* payload = js_new<TraceLoggerEventPayload>(textId, str);
     483           0 :     if (!payload) {
     484           0 :         js_free(str);
     485           0 :         return nullptr;
     486             :     }
     487             : 
     488           0 :     if (!textIdPayloads.putNew(textId, payload)) {
     489           0 :         js_delete(payload);
     490           0 :         payload = nullptr;
     491           0 :         return nullptr;
     492             :     }
     493             : 
     494           0 :     payload->use();
     495             : 
     496           0 :     nextTextId++;
     497             : 
     498           0 :     if (ptr) {
     499           0 :         if (!pointerMap.add(p, ptr, payload))
     500           0 :             return nullptr;
     501             : 
     502           0 :         payload->incPointerCount();
     503             :     }
     504             : 
     505           0 :     return payload;
     506             : }
     507             : 
     508             : TraceLoggerEventPayload*
     509           0 : TraceLoggerThreadState::getOrCreateEventPayload(JSScript* script)
     510             : {
     511           0 :     return getOrCreateEventPayload(script->filename(), script->lineno(), script->column(), nullptr);
     512             : }
     513             : 
     514             : void
     515           0 : TraceLoggerThreadState::purgeUnusedPayloads()
     516             : {
     517             :     // Care needs to be taken to maintain a coherent state in this function,
     518             :     // as payloads can have their use count change at any time from non-zero to
     519             :     // zero (but not the other way around; see TraceLoggerEventPayload::use()).
     520           0 :     LockGuard<Mutex> guard(lock);
     521             : 
     522             :     // Remove all the pointers to payloads that have no uses anymore
     523             :     // and decrease the pointer count of that payload.
     524           0 :     for (PointerHashMap::Enum e(pointerMap); !e.empty(); e.popFront()) {
     525           0 :         if (e.front().value()->uses() == 0) {
     526           0 :             e.front().value()->decPointerCount();
     527           0 :             e.removeFront();
     528             :         }
     529             :     }
     530             : 
     531             :     // Free all other payloads that have no uses anymore.
     532           0 :     for (TextIdHashMap::Enum e(textIdPayloads); !e.empty(); e.popFront()) {
     533           0 :         if (e.front().value()->uses() == 0 && e.front().value()->pointerCount() == 0) {
     534           0 :             js_delete(e.front().value());
     535           0 :             e.removeFront();
     536             :         }
     537             :     }
     538           0 : }
     539             : 
     540             : void
     541       41125 : TraceLoggerThread::startEvent(TraceLoggerTextId id) {
     542       41125 :     startEvent(uint32_t(id));
     543       41125 : }
     544             : 
     545             : void
     546       26417 : TraceLoggerThread::startEvent(const TraceLoggerEvent& event) {
     547       26417 :     if (!event.hasTextId()) {
     548           0 :         if (!enabled())
     549           0 :             return;
     550           0 :         startEvent(TraceLogger_Error);
     551             :         disable(/* force = */ true, "TraceLogger encountered an empty event. "
     552             :                                     "Potentially due to OOM during creation of "
     553           0 :                                     "this event. Disabling TraceLogger.");
     554           0 :         return;
     555             :     }
     556       26417 :     startEvent(event.textId());
     557             : }
     558             : 
     559             : void
     560       67542 : TraceLoggerThread::startEvent(uint32_t id)
     561             : {
     562       67542 :     MOZ_ASSERT(TLTextIdIsTreeEvent(id) || id == TraceLogger_Error);
     563       67542 :     MOZ_ASSERT(traceLoggerState);
     564       67542 :     if (!traceLoggerState->isTextIdEnabled(id))
     565       67542 :        return;
     566             : 
     567             : #ifdef DEBUG
     568           0 :     if (enabled_ > 0) {
     569           0 :         AutoEnterOOMUnsafeRegion oomUnsafe;
     570           0 :         if (!graphStack.append(id))
     571           0 :             oomUnsafe.crash("Could not add item to debug stack.");
     572             :     }
     573             : #endif
     574             : 
     575           0 :     if (graph.get()) {
     576           0 :         for (uint32_t otherId = graph->nextTextId(); otherId <= id; otherId++)
     577           0 :             graph->addTextId(otherId, maybeEventText(id));
     578             :     }
     579             : 
     580           0 :     log(id);
     581             : }
     582             : 
     583             : void
     584       42950 : TraceLoggerThread::stopEvent(TraceLoggerTextId id) {
     585       42950 :     stopEvent(uint32_t(id));
     586       42950 : }
     587             : 
     588             : void
     589       24445 : TraceLoggerThread::stopEvent(const TraceLoggerEvent& event) {
     590       24445 :     if (!event.hasTextId()) {
     591           0 :         stopEvent(TraceLogger_Error);
     592           0 :         return;
     593             :     }
     594       24445 :     stopEvent(event.textId());
     595             : }
     596             : 
     597             : void
     598       67395 : TraceLoggerThread::stopEvent(uint32_t id)
     599             : {
     600       67395 :     MOZ_ASSERT(TLTextIdIsTreeEvent(id) || id == TraceLogger_Error);
     601       67395 :     MOZ_ASSERT(traceLoggerState);
     602       67395 :     if (!traceLoggerState->isTextIdEnabled(id))
     603       67395 :         return;
     604             : 
     605             : #ifdef DEBUG
     606           0 :     if (enabled_ > 0 && !graphStack.empty()) {
     607           0 :         uint32_t prev = graphStack.popCopy();
     608           0 :         if (id == TraceLogger_Error || prev == TraceLogger_Error) {
     609             :             // When encountering an Error id the stack will most likely not be correct anymore.
     610             :             // Ignore this.
     611           0 :         } else if (id == TraceLogger_Engine) {
     612           0 :             MOZ_ASSERT(prev == TraceLogger_IonMonkey || prev == TraceLogger_Baseline ||
     613             :                        prev == TraceLogger_Interpreter);
     614           0 :         } else if (id == TraceLogger_Scripts) {
     615           0 :             MOZ_ASSERT(prev >= TraceLogger_Last);
     616           0 :         } else if (id >= TraceLogger_Last) {
     617           0 :             MOZ_ASSERT(prev >= TraceLogger_Last);
     618           0 :             if (prev != id) {
     619             :                 // Ignore if the text has been flushed already.
     620           0 :                 MOZ_ASSERT_IF(maybeEventText(prev), strcmp(eventText(id), eventText(prev)) == 0);
     621             :             }
     622             :         } else {
     623           0 :             MOZ_ASSERT(id == prev);
     624             :         }
     625             :     }
     626             : #endif
     627             : 
     628           0 :     log(TraceLogger_Stop);
     629             : }
     630             : 
     631             : void
     632           0 : TraceLoggerThread::logTimestamp(TraceLoggerTextId id)
     633             : {
     634           0 :     logTimestamp(uint32_t(id));
     635           0 : }
     636             : 
     637             : void
     638           0 : TraceLoggerThread::logTimestamp(uint32_t id)
     639             : {
     640           0 :     MOZ_ASSERT(id > TraceLogger_LastTreeItem && id < TraceLogger_Last);
     641           0 :     log(id);
     642           0 : }
     643             : 
     644             : void
     645           0 : TraceLoggerThread::log(uint32_t id)
     646             : {
     647           0 :     if (enabled_ == 0)
     648           0 :         return;
     649             : 
     650             : #ifdef DEBUG
     651           0 :     if (id == TraceLogger_Disable)
     652           0 :         graphStack.clear();
     653             : #endif
     654             : 
     655           0 :     MOZ_ASSERT(traceLoggerState);
     656             : 
     657             :     // We request for 3 items to add, since if we don't have enough room
     658             :     // we record the time it took to make more space. To log this information
     659             :     // we need 2 extra free entries.
     660           0 :     if (!events.hasSpaceForAdd(3)) {
     661           0 :         uint64_t start = rdtsc() - traceLoggerState->startupTime;
     662             : 
     663           0 :         if (!events.ensureSpaceBeforeAdd(3)) {
     664           0 :             if (graph.get())
     665           0 :                 graph->log(events);
     666             : 
     667           0 :             iteration_++;
     668           0 :             events.clear();
     669             : 
     670             :             // Periodically remove unused payloads from the global logger state.
     671           0 :             traceLoggerState->purgeUnusedPayloads();
     672             :         }
     673             : 
     674             :         // Log the time it took to flush the events as being from the
     675             :         // Tracelogger.
     676           0 :         if (graph.get()) {
     677           0 :             MOZ_ASSERT(events.hasSpaceForAdd(2));
     678           0 :             EventEntry& entryStart = events.pushUninitialized();
     679           0 :             entryStart.time = start;
     680           0 :             entryStart.textId = TraceLogger_Internal;
     681             : 
     682           0 :             EventEntry& entryStop = events.pushUninitialized();
     683           0 :             entryStop.time = rdtsc() - traceLoggerState->startupTime;
     684           0 :             entryStop.textId = TraceLogger_Stop;
     685             :         }
     686             : 
     687             :     }
     688             : 
     689           0 :     uint64_t time = rdtsc() - traceLoggerState->startupTime;
     690             : 
     691           0 :     EventEntry& entry = events.pushUninitialized();
     692           0 :     entry.time = time;
     693           0 :     entry.textId = id;
     694             : }
     695             : 
     696           0 : TraceLoggerThreadState::~TraceLoggerThreadState()
     697             : {
     698           0 :     while (TraceLoggerThread* logger = threadLoggers.popFirst())
     699           0 :         js_delete(logger);
     700             : 
     701           0 :     threadLoggers.clear();
     702             : 
     703           0 :     if (textIdPayloads.initialized()) {
     704           0 :         for (TextIdHashMap::Range r = textIdPayloads.all(); !r.empty(); r.popFront())
     705           0 :             js_delete(r.front().value());
     706             :     }
     707             : 
     708             : #ifdef DEBUG
     709           0 :     initialized = false;
     710             : #endif
     711           0 : }
     712             : 
     713             : static bool
     714         204 : ContainsFlag(const char* str, const char* flag)
     715             : {
     716         204 :     size_t flaglen = strlen(flag);
     717         204 :     const char* index = strstr(str, flag);
     718         204 :     while (index) {
     719           0 :         if ((index == str || index[-1] == ',') && (index[flaglen] == 0 || index[flaglen] == ','))
     720           0 :             return true;
     721           0 :         index = strstr(index + flaglen, flag);
     722             :     }
     723         204 :     return false;
     724             : }
     725             : 
     726             : bool
     727           3 : TraceLoggerThreadState::init()
     728             : {
     729           3 :     const char* env = getenv("TLLOG");
     730           3 :     if (!env)
     731           3 :         env = "";
     732             : 
     733           3 :     if (strstr(env, "help")) {
     734           0 :         fflush(nullptr);
     735             :         printf(
     736             :             "\n"
     737             :             "usage: TLLOG=option,option,option,... where options can be:\n"
     738             :             "\n"
     739             :             "Collections:\n"
     740             :             "  Default        Output all default. It includes:\n"
     741             :             "                 AnnotateScripts, Bailout, Baseline, BaselineCompilation, GC,\n"
     742             :             "                 GCAllocation, GCSweeping, Interpreter, IonAnalysis, IonCompilation,\n"
     743             :             "                 IonLinking, IonMonkey, MinorGC, Frontend, ParsingFull,\n"
     744             :             "                 ParsingSyntax, BytecodeEmission, IrregexpCompile, IrregexpExecute,\n"
     745             :             "                 Scripts, Engine, WasmCompilation\n"
     746             :             "\n"
     747             :             "  IonCompiler    Output all information about compilation. It includes:\n"
     748             :             "                 IonCompilation, IonLinking, PruneUnusedBranches, FoldTests,\n"
     749             :             "                 SplitCriticalEdges, RenumberBlocks, ScalarReplacement, \n"
     750             :             "                 DominatorTree, PhiAnalysis, MakeLoopsContiguous, ApplyTypes, \n"
     751             :             "                 EagerSimdUnbox, AliasAnalysis, GVN, LICM, Sincos, RangeAnalysis, \n"
     752             :             "                 LoopUnrolling, FoldLinearArithConstants, EffectiveAddressAnalysis, \n"
     753             :             "                 AlignmentMaskAnalysis, EliminateDeadCode, ReorderInstructions, \n"
     754             :             "                 EdgeCaseAnalysis, EliminateRedundantChecks, \n"
     755             :             "                 AddKeepAliveInstructions, GenerateLIR, RegisterAllocation, \n"
     756             :             "                 GenerateCode, Scripts, IonBuilderRestartLoop\n"
     757             :             "\n"
     758             :             "  VMSpecific     Output the specific name of the VM call\n"
     759             :             "\n"
     760             :             "  Frontend       Output all information about frontend compilation. It includes:\n"
     761             :             "                 Frontend, ParsingFull, ParsingSyntax, Tokenizing,\n"
     762             :             "                 BytecodeEmission, BytecodeFoldConstants, BytecodeNameFunctions\n"
     763             :             "Specific log items:\n"
     764           0 :         );
     765           0 :         for (uint32_t i = 1; i < TraceLogger_Last; i++) {
     766           0 :             TraceLoggerTextId id = TraceLoggerTextId(i);
     767           0 :             if (!TLTextIdIsTogglable(id))
     768           0 :                 continue;
     769           0 :             printf("  %s\n", TLTextIdString(id));
     770             :         }
     771           0 :         printf("\n");
     772           0 :         exit(0);
     773             :         /*NOTREACHED*/
     774             :     }
     775             : 
     776         216 :     for (uint32_t i = 1; i < TraceLogger_Last; i++) {
     777         213 :         TraceLoggerTextId id = TraceLoggerTextId(i);
     778         213 :         if (TLTextIdIsTogglable(id))
     779         195 :             enabledTextIds[i] = ContainsFlag(env, TLTextIdString(id));
     780             :         else
     781          18 :             enabledTextIds[i] = true;
     782             :     }
     783             : 
     784           3 :     if (ContainsFlag(env, "Default")) {
     785           0 :         enabledTextIds[TraceLogger_AnnotateScripts] = true;
     786           0 :         enabledTextIds[TraceLogger_Bailout] = true;
     787           0 :         enabledTextIds[TraceLogger_Baseline] = true;
     788           0 :         enabledTextIds[TraceLogger_BaselineCompilation] = true;
     789           0 :         enabledTextIds[TraceLogger_GC] = true;
     790           0 :         enabledTextIds[TraceLogger_GCAllocation] = true;
     791           0 :         enabledTextIds[TraceLogger_GCSweeping] = true;
     792           0 :         enabledTextIds[TraceLogger_Interpreter] = true;
     793           0 :         enabledTextIds[TraceLogger_IonAnalysis] = true;
     794           0 :         enabledTextIds[TraceLogger_IonCompilation] = true;
     795           0 :         enabledTextIds[TraceLogger_IonLinking] = true;
     796           0 :         enabledTextIds[TraceLogger_IonMonkey] = true;
     797           0 :         enabledTextIds[TraceLogger_MinorGC] = true;
     798           0 :         enabledTextIds[TraceLogger_Frontend] = true;
     799           0 :         enabledTextIds[TraceLogger_ParsingFull] = true;
     800           0 :         enabledTextIds[TraceLogger_ParsingSyntax] = true;
     801           0 :         enabledTextIds[TraceLogger_BytecodeEmission] = true;
     802           0 :         enabledTextIds[TraceLogger_IrregexpCompile] = true;
     803           0 :         enabledTextIds[TraceLogger_IrregexpExecute] = true;
     804           0 :         enabledTextIds[TraceLogger_Scripts] = true;
     805           0 :         enabledTextIds[TraceLogger_Engine] = true;
     806           0 :         enabledTextIds[TraceLogger_WasmCompilation] = true;
     807             :     }
     808             : 
     809           3 :     if (ContainsFlag(env, "IonCompiler")) {
     810           0 :         enabledTextIds[TraceLogger_IonCompilation] = true;
     811           0 :         enabledTextIds[TraceLogger_IonLinking] = true;
     812           0 :         enabledTextIds[TraceLogger_PruneUnusedBranches] = true;
     813           0 :         enabledTextIds[TraceLogger_FoldTests] = true;
     814           0 :         enabledTextIds[TraceLogger_SplitCriticalEdges] = true;
     815           0 :         enabledTextIds[TraceLogger_RenumberBlocks] = true;
     816           0 :         enabledTextIds[TraceLogger_ScalarReplacement] = true;
     817           0 :         enabledTextIds[TraceLogger_DominatorTree] = true;
     818           0 :         enabledTextIds[TraceLogger_PhiAnalysis] = true;
     819           0 :         enabledTextIds[TraceLogger_MakeLoopsContiguous] = true;
     820           0 :         enabledTextIds[TraceLogger_ApplyTypes] = true;
     821           0 :         enabledTextIds[TraceLogger_EagerSimdUnbox] = true;
     822           0 :         enabledTextIds[TraceLogger_AliasAnalysis] = true;
     823           0 :         enabledTextIds[TraceLogger_GVN] = true;
     824           0 :         enabledTextIds[TraceLogger_LICM] = true;
     825           0 :         enabledTextIds[TraceLogger_Sincos] = true;
     826           0 :         enabledTextIds[TraceLogger_RangeAnalysis] = true;
     827           0 :         enabledTextIds[TraceLogger_LoopUnrolling] = true;
     828           0 :         enabledTextIds[TraceLogger_FoldLinearArithConstants] = true;
     829           0 :         enabledTextIds[TraceLogger_EffectiveAddressAnalysis] = true;
     830           0 :         enabledTextIds[TraceLogger_AlignmentMaskAnalysis] = true;
     831           0 :         enabledTextIds[TraceLogger_EliminateDeadCode] = true;
     832           0 :         enabledTextIds[TraceLogger_ReorderInstructions] = true;
     833           0 :         enabledTextIds[TraceLogger_EdgeCaseAnalysis] = true;
     834           0 :         enabledTextIds[TraceLogger_EliminateRedundantChecks] = true;
     835           0 :         enabledTextIds[TraceLogger_AddKeepAliveInstructions] = true;
     836           0 :         enabledTextIds[TraceLogger_GenerateLIR] = true;
     837           0 :         enabledTextIds[TraceLogger_RegisterAllocation] = true;
     838           0 :         enabledTextIds[TraceLogger_GenerateCode] = true;
     839           0 :         enabledTextIds[TraceLogger_Scripts] = true;
     840           0 :         enabledTextIds[TraceLogger_IonBuilderRestartLoop] = true;
     841             :     }
     842             : 
     843           3 :     if (ContainsFlag(env, "Frontend")) {
     844           0 :         enabledTextIds[TraceLogger_Frontend] = true;
     845           0 :         enabledTextIds[TraceLogger_ParsingFull] = true;
     846           0 :         enabledTextIds[TraceLogger_ParsingSyntax] = true;
     847           0 :         enabledTextIds[TraceLogger_BytecodeEmission] = true;
     848           0 :         enabledTextIds[TraceLogger_BytecodeFoldConstants] = true;
     849           0 :         enabledTextIds[TraceLogger_BytecodeNameFunctions] = true;
     850             :     }
     851             : 
     852           3 :     enabledTextIds[TraceLogger_Interpreter] = enabledTextIds[TraceLogger_Engine];
     853           3 :     enabledTextIds[TraceLogger_Baseline] = enabledTextIds[TraceLogger_Engine];
     854           3 :     enabledTextIds[TraceLogger_IonMonkey] = enabledTextIds[TraceLogger_Engine];
     855             : 
     856           3 :     enabledTextIds[TraceLogger_Error] = true;
     857             : 
     858           3 :     const char* options = getenv("TLOPTIONS");
     859           3 :     if (options) {
     860           0 :         if (strstr(options, "help")) {
     861           0 :             fflush(nullptr);
     862             :             printf(
     863             :                 "\n"
     864             :                 "usage: TLOPTIONS=option,option,option,... where options can be:\n"
     865             :                 "\n"
     866             :                 "  EnableActiveThread      Start logging cooperating threads immediately.\n"
     867             :                 "  EnableOffThread         Start logging helper threads immediately.\n"
     868             :                 "  EnableGraph             Enable spewing the tracelogging graph to a file.\n"
     869             :                 "  Errors                  Report errors during tracing to stderr.\n"
     870           0 :             );
     871           0 :             printf("\n");
     872           0 :             exit(0);
     873             :             /*NOTREACHED*/
     874             :         }
     875             : 
     876           0 :         if (strstr(options, "EnableActiveThread"))
     877           0 :             cooperatingThreadEnabled = true;
     878           0 :         if (strstr(options, "EnableOffThread"))
     879           0 :             helperThreadEnabled = true;
     880           0 :         if (strstr(options, "EnableGraph"))
     881           0 :             graphSpewingEnabled = true;
     882           0 :         if (strstr(options, "Errors"))
     883           0 :             spewErrors = true;
     884             :     }
     885             : 
     886           3 :     if (!pointerMap.init())
     887           0 :         return false;
     888           3 :     if (!textIdPayloads.init())
     889           0 :         return false;
     890             : 
     891           3 :     startupTime = rdtsc();
     892             : 
     893             : #ifdef DEBUG
     894           3 :     initialized = true;
     895             : #endif
     896             : 
     897           3 :     return true;
     898             : }
     899             : 
     900             : void
     901           0 : TraceLoggerThreadState::enableTextId(JSContext* cx, uint32_t textId)
     902             : {
     903           0 :     MOZ_ASSERT(TLTextIdIsTogglable(textId));
     904             : 
     905           0 :     if (enabledTextIds[textId])
     906           0 :         return;
     907             : 
     908           0 :     ReleaseAllJITCode(cx->runtime()->defaultFreeOp());
     909             : 
     910           0 :     enabledTextIds[textId] = true;
     911           0 :     if (textId == TraceLogger_Engine) {
     912           0 :         enabledTextIds[TraceLogger_IonMonkey] = true;
     913           0 :         enabledTextIds[TraceLogger_Baseline] = true;
     914           0 :         enabledTextIds[TraceLogger_Interpreter] = true;
     915             :     }
     916             : 
     917           0 :     if (textId == TraceLogger_Scripts)
     918           0 :         jit::ToggleBaselineTraceLoggerScripts(cx->runtime(), true);
     919           0 :     if (textId == TraceLogger_Engine)
     920           0 :         jit::ToggleBaselineTraceLoggerEngine(cx->runtime(), true);
     921             : 
     922             : }
     923             : void
     924           0 : TraceLoggerThreadState::disableTextId(JSContext* cx, uint32_t textId)
     925             : {
     926           0 :     MOZ_ASSERT(TLTextIdIsTogglable(textId));
     927             : 
     928           0 :     if (!enabledTextIds[textId])
     929           0 :         return;
     930             : 
     931           0 :     ReleaseAllJITCode(cx->runtime()->defaultFreeOp());
     932             : 
     933           0 :     enabledTextIds[textId] = false;
     934           0 :     if (textId == TraceLogger_Engine) {
     935           0 :         enabledTextIds[TraceLogger_IonMonkey] = false;
     936           0 :         enabledTextIds[TraceLogger_Baseline] = false;
     937           0 :         enabledTextIds[TraceLogger_Interpreter] = false;
     938             :     }
     939             : 
     940           0 :     if (textId == TraceLogger_Scripts)
     941           0 :         jit::ToggleBaselineTraceLoggerScripts(cx->runtime(), false);
     942           0 :     if (textId == TraceLogger_Engine)
     943           0 :         jit::ToggleBaselineTraceLoggerEngine(cx->runtime(), false);
     944             : }
     945             : 
     946             : TraceLoggerThread*
     947       41271 : js::TraceLoggerForCurrentThread(JSContext* maybecx)
     948             : {
     949       41271 :     if (!EnsureTraceLoggerState())
     950           0 :         return nullptr;
     951       41271 :     return traceLoggerState->forCurrentThread(maybecx);
     952             : }
     953             : 
     954             : TraceLoggerThread*
     955       41271 : TraceLoggerThreadState::forCurrentThread(JSContext* maybecx)
     956             : {
     957       41271 :     MOZ_ASSERT(initialized);
     958       41271 :     MOZ_ASSERT_IF(maybecx, maybecx == TlsContext.get());
     959             : 
     960       41271 :     JSContext* cx = maybecx ? maybecx : TlsContext.get();
     961       41271 :     if (!cx)
     962           0 :         return nullptr;
     963             : 
     964       41271 :     if (!cx->traceLogger) {
     965          44 :         LockGuard<Mutex> guard(lock);
     966             : 
     967          22 :         TraceLoggerThread* logger = js_new<TraceLoggerThread>();
     968          22 :         if (!logger)
     969           0 :             return nullptr;
     970             : 
     971          22 :         if (!logger->init()) {
     972           0 :             js_delete(logger);
     973           0 :             return nullptr;
     974             :         }
     975             : 
     976          22 :         threadLoggers.insertFront(logger);
     977          22 :         cx->traceLogger = logger;
     978             : 
     979          22 :         if (graphSpewingEnabled)
     980           0 :             logger->initGraph();
     981             : 
     982          22 :         if (CurrentHelperThread() ? helperThreadEnabled : cooperatingThreadEnabled)
     983           0 :             logger->enable();
     984             :     }
     985             : 
     986       41271 :     return cx->traceLogger;
     987             : }
     988             : 
     989             : void
     990           0 : TraceLoggerThreadState::destroyLogger(TraceLoggerThread* logger)
     991             : {
     992           0 :     MOZ_ASSERT(initialized);
     993           0 :     MOZ_ASSERT(logger);
     994           0 :     LockGuard<Mutex> guard(lock);
     995             : 
     996           0 :     logger->remove();
     997           0 :     js_delete(logger);
     998           0 : }
     999             : 
    1000             : bool
    1001        6786 : js::TraceLogTextIdEnabled(uint32_t textId)
    1002             : {
    1003        6786 :     if (!EnsureTraceLoggerState())
    1004           0 :         return false;
    1005        6786 :     return traceLoggerState->isTextIdEnabled(textId);
    1006             : }
    1007             : 
    1008             : void
    1009           0 : js::TraceLogEnableTextId(JSContext* cx, uint32_t textId)
    1010             : {
    1011           0 :     if (!EnsureTraceLoggerState())
    1012           0 :         return;
    1013           0 :     traceLoggerState->enableTextId(cx, textId);
    1014             : }
    1015             : void
    1016           0 : js::TraceLogDisableTextId(JSContext* cx, uint32_t textId)
    1017             : {
    1018           0 :     if (!EnsureTraceLoggerState())
    1019           0 :         return;
    1020           0 :     traceLoggerState->disableTextId(cx, textId);
    1021             : }
    1022             : 
    1023       13088 : TraceLoggerEvent::TraceLoggerEvent(TraceLoggerTextId type, JSScript* script)
    1024       13088 :   : TraceLoggerEvent(type, script->filename(), script->lineno(), script->column())
    1025       13088 : { }
    1026             : 
    1027       26417 : TraceLoggerEvent::TraceLoggerEvent(TraceLoggerTextId type, const char* filename, size_t line,
    1028       26417 :                                    size_t column)
    1029       26417 :   : payload_()
    1030             : {
    1031       26417 :     MOZ_ASSERT(type == TraceLogger_Scripts || type == TraceLogger_AnnotateScripts ||
    1032             :                type == TraceLogger_InlinedScripts || type == TraceLogger_Frontend);
    1033             : 
    1034       26417 :     if (!traceLoggerState)
    1035           0 :         return;
    1036             : 
    1037             :     // Only log scripts when enabled, otherwise use the more generic type
    1038             :     // (which will get filtered out).
    1039       26417 :     if (!traceLoggerState->isTextIdEnabled(type)) {
    1040       26417 :         payload_.setTextId(type);
    1041       26417 :         return;
    1042             :     }
    1043             : 
    1044           0 :     payload_.setEventPayload(
    1045           0 :         traceLoggerState->getOrCreateEventPayload(filename, line, column, nullptr));
    1046             : }
    1047             : 
    1048           0 : TraceLoggerEvent::TraceLoggerEvent(const char* text)
    1049           0 :   : payload_()
    1050             : {
    1051           0 :     if (traceLoggerState)
    1052           0 :         payload_.setEventPayload(traceLoggerState->getOrCreateEventPayload(text));
    1053           0 : }
    1054             : 
    1055       53914 : TraceLoggerEvent::~TraceLoggerEvent()
    1056             : {
    1057       26957 :     if (hasExtPayload())
    1058           0 :         extPayload()->release();
    1059       26957 : }
    1060             : 
    1061             : uint32_t
    1062       50862 : TraceLoggerEvent::textId() const
    1063             : {
    1064       50862 :     MOZ_ASSERT(hasTextId());
    1065       50862 :     if (hasExtPayload())
    1066           0 :         return extPayload()->textId();
    1067       50862 :     return payload_.textId();
    1068             : }
    1069             : 
    1070             : TraceLoggerEvent&
    1071           0 : TraceLoggerEvent::operator=(const TraceLoggerEvent& other)
    1072             : {
    1073           0 :     if (other.hasExtPayload())
    1074           0 :         other.extPayload()->use();
    1075           0 :     if (hasExtPayload())
    1076           0 :         extPayload()->release();
    1077             : 
    1078           0 :     payload_ = other.payload_;
    1079             : 
    1080           0 :     return *this;
    1081             : }
    1082             : 
    1083           0 : TraceLoggerEvent::TraceLoggerEvent(const TraceLoggerEvent& other)
    1084           0 :   : payload_(other.payload_)
    1085             : {
    1086           0 :     if (hasExtPayload())
    1087           0 :         extPayload()->use();
    1088           0 : }

Generated by: LCOV version 1.13