js/src/vm/TraceLogging.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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/. */
     7 #include "vm/TraceLogging.h"
     9 #include "mozilla/DebugOnly.h"
    11 #include <string.h>
    13 #include "jsapi.h"
    14 #include "jsscript.h"
    16 #include "jit/CompileWrappers.h"
    17 #include "vm/Runtime.h"
    19 using namespace js;
    21 #ifndef TRACE_LOG_DIR
    22 # if defined(_WIN32)
    23 #  define TRACE_LOG_DIR ""
    24 # else
    25 #  define TRACE_LOG_DIR "/tmp/"
    26 # endif
    27 #endif
    29 #if defined(__i386__)
    30 static __inline__ uint64_t
    31 rdtsc(void)
    32 {
    33     uint64_t x;
    34     __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
    35     return x;
    36 }
    37 #elif defined(__x86_64__)
    38 static __inline__ uint64_t
    39 rdtsc(void)
    40 {
    41     unsigned hi, lo;
    42     __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
    43     return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 );
    44 }
    45 #elif defined(__powerpc__)
    46 static __inline__ uint64_t
    47 rdtsc(void)
    48 {
    49     uint64_t result=0;
    50     uint32_t upper, lower,tmp;
    51     __asm__ volatile(
    52             "0:                  \n"
    53             "\tmftbu   %0           \n"
    54             "\tmftb    %1           \n"
    55             "\tmftbu   %2           \n"
    56             "\tcmpw    %2,%0        \n"
    57             "\tbne     0b         \n"
    58             : "=r"(upper),"=r"(lower),"=r"(tmp)
    59             );
    60     result = upper;
    61     result = result<<32;
    62     result = result|lower;
    64     return result;
    65 }
    66 #endif
    68 TraceLogging traceLoggers;
    70 static const char* const text[] =
    71 {
    72     "TraceLogger failed to process text",
    73 #define NAME(x) #x,
    74     TRACELOGGER_TEXT_ID_LIST(NAME)
    75 #undef NAME
    76 };
    78 TraceLogger::TraceLogger()
    79  : enabled(false),
    80    enabledTimes(0),
    81    failed(false),
    82    nextTextId(0),
    83    treeOffset(0),
    84    top(nullptr)
    85 { }
    87 bool
    88 TraceLogger::init(uint32_t loggerId)
    89 {
    90     if (!pointerMap.init())
    91         return false;
    92     if (!tree.init())
    93         return false;
    94     if (!stack.init())
    95         return false;
    96     if (!events.init())
    97         return false;
    99     MOZ_ASSERT(loggerId <= 999);
   101     char dictFilename[sizeof TRACE_LOG_DIR "tl-dict.100.json"];
   102     sprintf(dictFilename, TRACE_LOG_DIR "tl-dict.%d.json", loggerId);
   103     dictFile = fopen(dictFilename, "w");
   104     if (!dictFile)
   105         return false;
   107     char treeFilename[sizeof TRACE_LOG_DIR "tl-tree.100.tl"];
   108     sprintf(treeFilename, TRACE_LOG_DIR "tl-tree.%d.tl", loggerId);
   109     treeFile = fopen(treeFilename, "wb");
   110     if (!treeFile) {
   111         fclose(dictFile);
   112         dictFile = nullptr;
   113         return false;
   114     }
   116     char eventFilename[sizeof TRACE_LOG_DIR "tl-event.100.tl"];
   117     sprintf(eventFilename, TRACE_LOG_DIR "tl-event.%d.tl", loggerId);
   118     eventFile = fopen(eventFilename, "wb");
   119     if (!eventFile) {
   120         fclose(dictFile);
   121         fclose(treeFile);
   122         dictFile = nullptr;
   123         treeFile = nullptr;
   124         return false;
   125     }
   127     uint64_t start = rdtsc() - traceLoggers.startupTime;
   129     TreeEntry &treeEntry = tree.pushUninitialized();
   130     treeEntry.setStart(start);
   131     treeEntry.setStop(0);
   132     treeEntry.setTextId(0);
   133     treeEntry.setHasChildren(false);
   134     treeEntry.setNextId(0);
   136     StackEntry &stackEntry = stack.pushUninitialized();
   137     stackEntry.setTreeId(0);
   138     stackEntry.setLastChildId(0);
   139     stackEntry.setActive(true);
   141     int written = fprintf(dictFile, "[");
   142     if (written < 0)
   143         fprintf(stderr, "TraceLogging: Error while writing.\n");
   145     // Eagerly create the default textIds, to match their Tracelogger::TextId.
   146     for (uint32_t i = 0; i < LAST; i++) {
   147         mozilla::DebugOnly<uint32_t> textId = createTextId(text[i]);
   148         MOZ_ASSERT(textId == i);
   149     }
   151     enabled = true;
   152     enabledTimes = 1;
   153     return true;
   154 }
   156 bool
   157 TraceLogger::enable()
   158 {
   159     if (enabled) {
   160         enabledTimes++;
   161         return true;
   162     }
   164     if (failed)
   165         return false;
   167     if (!tree.ensureSpaceBeforeAdd(stack.size())) {
   168         if (!flush()) {
   169             fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
   170             failed = true;
   171             return false;
   172         }
   173         if (!tree.ensureSpaceBeforeAdd(stack.size())) {
   174             fprintf(stderr, "TraceLogging: Couldn't reserve enough space.\n");
   175             failed = true;
   176             return false;
   177         }
   178     }
   180     uint64_t start = rdtsc() - traceLoggers.startupTime;
   181     StackEntry *parent = &stack[0];
   182     for (uint32_t i = 1; i < stack.size(); i++) {
   183         if (!traceLoggers.isTextIdEnabled(stack[i].textId()))
   184             continue;
   185 #ifdef DEBUG
   186         TreeEntry entry;
   187         if (!getTreeEntry(parent->treeId(), &entry))
   188             return false;
   189 #endif
   191         if (parent->lastChildId() == 0) {
   192             MOZ_ASSERT(!entry.hasChildren());
   193             MOZ_ASSERT(parent->treeId() == tree.currentId() + treeOffset);
   194             if (!updateHasChildren(parent->treeId())) {
   195                 fprintf(stderr, "TraceLogging: Couldn't update an entry.\n");
   196                 failed = true;
   197                 return false;
   198             }
   199         } else {
   200             MOZ_ASSERT(entry.hasChildren() == 1);
   201             if (!updateNextId(parent->lastChildId(), tree.nextId() + treeOffset)) {
   202                 fprintf(stderr, "TraceLogging: Couldn't update an entry.\n");
   203                 failed = true;
   204                 return false;
   205             }
   206         }
   208         TreeEntry &treeEntry = tree.pushUninitialized();
   209         treeEntry.setStart(start);
   210         treeEntry.setStop(0);
   211         treeEntry.setTextId(stack[i].textId());
   212         treeEntry.setHasChildren(false);
   213         treeEntry.setNextId(0);
   215         stack[i].setActive(true);
   216         stack[i].setTreeId(tree.currentId() + treeOffset);
   218         parent->setLastChildId(tree.currentId() + treeOffset);
   220         parent = &stack[i];
   221     }
   223     enabled = true;
   224     enabledTimes = 1;
   226     return true;
   227 }
   229 bool
   230 TraceLogger::disable()
   231 {
   232     if (failed)
   233         return false;
   235     if (!enabled)
   236         return true;
   238     if (enabledTimes > 1) {
   239         enabledTimes--;
   240         return true;
   241     }
   243     uint64_t stop = rdtsc() - traceLoggers.startupTime;
   244     for (uint32_t i = 1; i < stack.size(); i++) {
   245         if (!stack[i].active())
   246             continue;
   248         if (!updateStop(stack[i].treeId(), stop)) {
   249             fprintf(stderr, "TraceLogging: Failed to stop an event.\n");
   250             failed = true;
   251             enabled = false;
   252             return false;
   253         }
   255         stack[i].setActive(false);
   256     }
   259     enabled = false;
   260     enabledTimes = 0;
   262     return true;
   263 }
   265 bool
   266 TraceLogger::flush()
   267 {
   268     MOZ_ASSERT(!failed);
   270     if (treeFile) {
   271         // Format data in big endian.
   272         for (size_t i = 0; i < tree.size(); i++)
   273             entryToBigEndian(&tree[i]);
   275         int success = fseek(treeFile, 0, SEEK_END);
   276         if (success != 0)
   277             return false;
   279         size_t bytesWritten = fwrite(tree.data(), sizeof(TreeEntry), tree.size(), treeFile);
   280         if (bytesWritten < tree.size())
   281             return false;
   283         treeOffset += tree.currentId();
   284         tree.clear();
   285     }
   287     if (eventFile) {
   288         // Format data in big endian
   289         for (size_t i = 0; i < events.size(); i++) {
   290             events[i].time = htobe64(events[i].time);
   291             events[i].textId = htobe64(events[i].textId);
   292         }
   294         size_t bytesWritten = fwrite(events.data(), sizeof(EventEntry), events.size(), eventFile);
   295         if (bytesWritten < events.size())
   296             return false;
   297         events.clear();
   298     }
   300     return true;
   301 }
   303 TraceLogger::~TraceLogger()
   304 {
   305     // Write dictionary to disk
   306     if (dictFile) {
   307         int written = fprintf(dictFile, "]");
   308         if (written < 0)
   309             fprintf(stderr, "TraceLogging: Error while writing.\n");
   310         fclose(dictFile);
   312         dictFile = nullptr;
   313     }
   315     if (!failed && treeFile) {
   316         // Make sure every start entry has a corresponding stop value.
   317         // We temporary enable logging for this. Stop doesn't need any extra data,
   318         // so is safe to do, even when we encountered OOM.
   319         enabled = true;
   320         while (stack.size() > 0)
   321             stopEvent();
   322         enabled = false;
   323     }
   325     if (!failed && !flush()) {
   326         fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
   327         enabled = false;
   328         failed = true;
   329     }
   331     if (treeFile) {
   332         fclose(treeFile);
   333         treeFile = nullptr;
   334     }
   336     if (eventFile) {
   337         fclose(eventFile);
   338         eventFile = nullptr;
   339     }
   340 }
   342 uint32_t
   343 TraceLogger::createTextId(const char *text)
   344 {
   345     assertNoQuotes(text);
   347     PointerHashMap::AddPtr p = pointerMap.lookupForAdd((const void *)text);
   348     if (p)
   349         return p->value();
   351     uint32_t textId = nextTextId++;
   352     if (!pointerMap.add(p, text, textId))
   353         return TraceLogger::TL_Error;
   355     int written;
   356     if (textId > 0)
   357         written = fprintf(dictFile, ",\n\"%s\"", text);
   358     else
   359         written = fprintf(dictFile, "\"%s\"", text);
   361     if (written < 0)
   362         return TraceLogger::TL_Error;
   364     return textId;
   365 }
   367 uint32_t
   368 TraceLogger::createTextId(JSScript *script)
   369 {
   370     assertNoQuotes(script->filename());
   372     PointerHashMap::AddPtr p = pointerMap.lookupForAdd(script);
   373     if (p)
   374         return p->value();
   376     uint32_t textId = nextTextId++;
   377     if (!pointerMap.add(p, script, textId))
   378         return TraceLogger::TL_Error;
   380     int written;
   381     if (textId > 0) {
   382         written = fprintf(dictFile, ",\n\"script %s:%d:%d\"", script->filename(),
   383                           script->lineno(), script->column());
   384     } else {
   385         written = fprintf(dictFile, "\"script %s:%d:%d\"", script->filename(),
   386                           script->lineno(), script->column());
   387     }
   389     if (written < 0)
   390         return TraceLogger::TL_Error;
   392     return textId;
   393 }
   395 uint32_t
   396 TraceLogger::createTextId(const JS::ReadOnlyCompileOptions &compileOptions)
   397 {
   398     assertNoQuotes(compileOptions.filename());
   400     PointerHashMap::AddPtr p = pointerMap.lookupForAdd(&compileOptions);
   401     if (p)
   402         return p->value();
   404     uint32_t textId = nextTextId++;
   405     if (!pointerMap.add(p, &compileOptions, textId))
   406         return TraceLogger::TL_Error;
   408     int written;
   409     if (textId > 0) {
   410         written = fprintf(dictFile, ",\n\"script %s:%d:%d\"", compileOptions.filename(),
   411                           compileOptions.lineno, compileOptions.column);
   412     } else {
   413         written = fprintf(dictFile, "\"script %s:%d:%d\"", compileOptions.filename(),
   414                           compileOptions.lineno, compileOptions.column);
   415     }
   417     if (written < 0)
   418         return TraceLogger::TL_Error;
   420     return textId;
   421 }
   423 void
   424 TraceLogger::logTimestamp(uint32_t id)
   425 {
   426     if (!enabled)
   427         return;
   429     if (!events.ensureSpaceBeforeAdd()) {
   430         fprintf(stderr, "TraceLogging: Disabled a tracelogger due to OOM.\n");
   431         enabled = false;
   432         return;
   433     }
   435     uint64_t time = rdtsc() - traceLoggers.startupTime;
   437     EventEntry &entry = events.pushUninitialized();
   438     entry.time = time;
   439     entry.textId = id;
   440 }
   442 void
   443 TraceLogger::entryToBigEndian(TreeEntry *entry)
   444 {
   445     entry->start_ = htobe64(entry->start_);
   446     entry->stop_ = htobe64(entry->stop_);
   447     entry->u.value_ = htobe32((entry->u.s.textId_ << 1) + entry->u.s.hasChildren_);
   448     entry->nextId_ = htobe32(entry->nextId_);
   449 }
   451 void
   452 TraceLogger::entryToSystemEndian(TreeEntry *entry)
   453 {
   454     entry->start_ = be64toh(entry->start_);
   455     entry->stop_ = be64toh(entry->stop_);
   457     uint32_t data = be32toh(entry->u.value_);
   458     entry->u.s.textId_ = data >> 1;
   459     entry->u.s.hasChildren_ = data & 0x1;
   461     entry->nextId_ = be32toh(entry->nextId_);
   462 }
   464 bool
   465 TraceLogger::getTreeEntry(uint32_t treeId, TreeEntry *entry)
   466 {
   467     // Entry is still in memory
   468     if (treeId >= treeOffset) {
   469         *entry = tree[treeId];
   470         return true;
   471     }
   473     int success = fseek(treeFile, treeId * sizeof(TreeEntry), SEEK_SET);
   474     if (success != 0)
   475         return false;
   477     size_t itemsRead = fread((void *)entry, sizeof(TreeEntry), 1, treeFile);
   478     if (itemsRead < 1)
   479         return false;
   481     entryToSystemEndian(entry);
   482     return true;
   483 }
   485 bool
   486 TraceLogger::saveTreeEntry(uint32_t treeId, TreeEntry *entry)
   487 {
   488     int success = fseek(treeFile, treeId * sizeof(TreeEntry), SEEK_SET);
   489     if (success != 0)
   490         return false;
   492     entryToBigEndian(entry);
   494     size_t itemsWritten = fwrite(entry, sizeof(TreeEntry), 1, treeFile);
   495     if (itemsWritten < 1)
   496         return false;
   498     return true;
   499 }
   501 bool
   502 TraceLogger::updateHasChildren(uint32_t treeId, bool hasChildren)
   503 {
   504     if (treeId < treeOffset) {
   505         TreeEntry entry;
   506         if (!getTreeEntry(treeId, &entry))
   507             return false;
   508         entry.setHasChildren(hasChildren);
   509         if (!saveTreeEntry(treeId, &entry))
   510             return false;
   511         return true;
   512     }
   514     tree[treeId - treeOffset].setHasChildren(hasChildren);
   515     return true;
   516 }
   518 bool
   519 TraceLogger::updateNextId(uint32_t treeId, uint32_t nextId)
   520 {
   521     if (treeId < treeOffset) {
   522         TreeEntry entry;
   523         if (!getTreeEntry(treeId, &entry))
   524             return false;
   525         entry.setNextId(nextId);
   526         if (!saveTreeEntry(treeId, &entry))
   527             return false;
   528         return true;
   529     }
   531     tree[treeId - treeOffset].setNextId(nextId);
   532     return true;
   533 }
   535 bool
   536 TraceLogger::updateStop(uint32_t treeId, uint64_t timestamp)
   537 {
   538     if (treeId < treeOffset) {
   539         TreeEntry entry;
   540         if (!getTreeEntry(treeId, &entry))
   541             return false;
   542         entry.setStop(timestamp);
   543         if (!saveTreeEntry(treeId, &entry))
   544             return false;
   545         return true;
   546     }
   548     tree[treeId - treeOffset].setStop(timestamp);
   549     return true;
   550 }
   552 void
   553 TraceLogger::startEvent(uint32_t id)
   554 {
   555     if (failed)
   556         return;
   558     if (!stack.ensureSpaceBeforeAdd()) {
   559         fprintf(stderr, "TraceLogging: Failed to allocate space to keep track of the stack.\n");
   560         enabled = false;
   561         failed = true;
   562         return;
   563     }
   565     if (!enabled) {
   566         StackEntry &stackEntry = stack.pushUninitialized();
   567         stackEntry.setTreeId(tree.currentId() + treeOffset);
   568         stackEntry.setLastChildId(0);
   569         stackEntry.setTextId(id);
   570         stackEntry.setActive(false);
   571         return;
   572     }
   574     if (!tree.ensureSpaceBeforeAdd()) {
   575         uint64_t start = rdtsc() - traceLoggers.startupTime;
   576         if (!flush()) {
   577             fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
   578             enabled = false;
   579             failed = true;
   580             return;
   581         }
   583         // Log the time it took to flush the events as being from the
   584         // Tracelogger.
   585         if (!startEvent(TraceLogger::TL, start)) {
   586             fprintf(stderr, "TraceLogging: Failed to start an event.\n");
   587             enabled = false;
   588             failed = true;
   589             return;
   590         }
   591         stopEvent();
   592     }
   594     uint64_t start = rdtsc() - traceLoggers.startupTime;
   595     if (!startEvent(id, start)) {
   596         fprintf(stderr, "TraceLogging: Failed to start an event.\n");
   597         enabled = false;
   598         failed = true;
   599         return;
   600     }
   601 }
   603 TraceLogger::StackEntry &
   604 TraceLogger::getActiveAncestor()
   605 {
   606     uint32_t parentId = stack.currentId();
   607     while (!stack[parentId].active())
   608         parentId--;
   609     return stack[parentId];
   610 }
   612 bool
   613 TraceLogger::startEvent(uint32_t id, uint64_t timestamp)
   614 {
   615     // When a textId is disabled, a stack entry still needs to be pushed,
   616     // together with an annotation that nothing needs to get done when receiving
   617     // the stop event.
   618     if (!traceLoggers.isTextIdEnabled(id)) {
   619         StackEntry &stackEntry = stack.pushUninitialized();
   620         stackEntry.setActive(false);
   621         return true;
   622     }
   624     // Patch up the tree to be correct. There are two scenarios:
   625     // 1) Parent has no children yet. So update parent to include children.
   626     // 2) Parent has already children. Update last child to link to the new
   627     //    child.
   628     StackEntry &parent = getActiveAncestor();
   629 #ifdef DEBUG
   630     TreeEntry entry;
   631     if (!getTreeEntry(parent.treeId(), &entry))
   632         return false;
   633 #endif
   635     if (parent.lastChildId() == 0) {
   636         MOZ_ASSERT(!entry.hasChildren());
   637         MOZ_ASSERT(parent.treeId() == tree.currentId() + treeOffset);
   639         if (!updateHasChildren(parent.treeId()))
   640             return false;
   641     } else {
   642         MOZ_ASSERT(entry.hasChildren());
   644         if (!updateNextId(parent.lastChildId(), tree.nextId() + treeOffset))
   645             return false;
   646     }
   648     // Add a new tree entry.
   649     TreeEntry &treeEntry = tree.pushUninitialized();
   650     treeEntry.setStart(timestamp);
   651     treeEntry.setStop(0);
   652     treeEntry.setTextId(id);
   653     treeEntry.setHasChildren(false);
   654     treeEntry.setNextId(0);
   656     // Add a new stack entry.
   657     StackEntry &stackEntry = stack.pushUninitialized();
   658     stackEntry.setTreeId(tree.currentId() + treeOffset);
   659     stackEntry.setLastChildId(0);
   660     stackEntry.setActive(true);
   662     // Set the last child of the parent to this newly added entry.
   663     parent.setLastChildId(tree.currentId() + treeOffset);
   665     return true;
   666 }
   668 void
   669 TraceLogger::stopEvent(uint32_t id)
   670 {
   671 #ifdef DEBUG
   672     TreeEntry entry;
   673     MOZ_ASSERT_IF(stack.current().active(), getTreeEntry(stack.current().treeId(), &entry));
   674     MOZ_ASSERT_IF(stack.current().active(), entry.textId() == id);
   675 #endif
   676     stopEvent();
   677 }
   679 void
   680 TraceLogger::stopEvent()
   681 {
   682     if (enabled && stack.current().active()) {
   683         uint64_t stop = rdtsc() - traceLoggers.startupTime;
   684         if (!updateStop(stack.current().treeId(), stop)) {
   685             fprintf(stderr, "TraceLogging: Failed to stop an event.\n");
   686             enabled = false;
   687             failed = true;
   688             return;
   689         }
   690     }
   691     stack.pop();
   692 }
   694 TraceLogging::TraceLogging()
   695 {
   696     initialized = false;
   697     enabled = false;
   698     mainThreadEnabled = true;
   699     offThreadEnabled = true;
   700     loggerId = 0;
   702 #ifdef JS_THREADSAFE
   703     lock = PR_NewLock();
   704     if (!lock)
   705         MOZ_CRASH();
   706 #endif // JS_THREADSAFE
   707 }
   709 TraceLogging::~TraceLogging()
   710 {
   711     if (out) {
   712         fprintf(out, "]");
   713         fclose(out);
   714         out = nullptr;
   715     }
   717     for (size_t i = 0; i < mainThreadLoggers.length(); i++)
   718         delete mainThreadLoggers[i];
   720     mainThreadLoggers.clear();
   722 #ifdef JS_THREADSAFE
   723     if (threadLoggers.initialized()) {
   724         for (ThreadLoggerHashMap::Range r = threadLoggers.all(); !r.empty(); r.popFront())
   725             delete r.front().value();
   727         threadLoggers.finish();
   728     }
   730     if (lock) {
   731         PR_DestroyLock(lock);
   732         lock = nullptr;
   733     }
   734 #endif // JS_THREADSAFE
   736     enabled = false;
   737 }
   739 static bool
   740 ContainsFlag(const char *str, const char *flag)
   741 {
   742     size_t flaglen = strlen(flag);
   743     const char *index = strstr(str, flag);
   744     while (index) {
   745         if ((index == str || index[-1] == ',') && (index[flaglen] == 0 || index[flaglen] == ','))
   746             return true;
   747         index = strstr(index + flaglen, flag);
   748     }
   749     return false;
   750 }
   752 bool
   753 TraceLogging::lazyInit()
   754 {
   755     if (initialized)
   756         return enabled;
   758     initialized = true;
   760     out = fopen(TRACE_LOG_DIR "tl-data.json", "w");
   761     if (!out)
   762         return false;
   763     fprintf(out, "[");
   765 #ifdef JS_THREADSAFE
   766     if (!threadLoggers.init())
   767         return false;
   768 #endif // JS_THREADSAFE
   770     const char *env = getenv("TLLOG");
   771     if (!env)
   772         env = "";
   774     if (strstr(env, "help")) {
   775         fflush(nullptr);
   776         printf(
   777             "\n"
   778             "usage: TLLOG=option,option,option,... where options can be:\n"
   779             "\n"
   780             "Collections:\n"
   781             "  Default        Output all default\n"
   782             "  IonCompiler    Output all information about compilation\n"
   783             "\n"
   784             "Specific log items:\n"
   785         );
   786         for (uint32_t i = 1; i < TraceLogger::LAST; i++) {
   787             printf("  %s\n", text[i]);
   788         }
   789         printf("\n");
   790         exit(0);
   791         /*NOTREACHED*/
   792     }
   794     for (uint32_t i = 1; i < TraceLogger::LAST; i++)
   795         enabledTextIds[i] = ContainsFlag(env, text[i]);
   797     enabledTextIds[TraceLogger::TL_Error] = true;
   798     enabledTextIds[TraceLogger::TL] = true;
   800     if (ContainsFlag(env, "Default") || strlen(env) == 0) {
   801         enabledTextIds[TraceLogger::Bailout] = true;
   802         enabledTextIds[TraceLogger::Baseline] = true;
   803         enabledTextIds[TraceLogger::BaselineCompilation] = true;
   804         enabledTextIds[TraceLogger::GC] = true;
   805         enabledTextIds[TraceLogger::GCAllocation] = true;
   806         enabledTextIds[TraceLogger::GCSweeping] = true;
   807         enabledTextIds[TraceLogger::Interpreter] = true;
   808         enabledTextIds[TraceLogger::IonCompilation] = true;
   809         enabledTextIds[TraceLogger::IonLinking] = true;
   810         enabledTextIds[TraceLogger::IonMonkey] = true;
   811         enabledTextIds[TraceLogger::MinorGC] = true;
   812         enabledTextIds[TraceLogger::ParserCompileFunction] = true;
   813         enabledTextIds[TraceLogger::ParserCompileLazy] = true;
   814         enabledTextIds[TraceLogger::ParserCompileScript] = true;
   815         enabledTextIds[TraceLogger::YarrCompile] = true;
   816         enabledTextIds[TraceLogger::YarrInterpret] = true;
   817         enabledTextIds[TraceLogger::YarrJIT] = true;
   818     }
   820     if (ContainsFlag(env, "IonCompiler") || strlen(env) == 0) {
   821         enabledTextIds[TraceLogger::IonCompilation] = true;
   822         enabledTextIds[TraceLogger::IonLinking] = true;
   823         enabledTextIds[TraceLogger::SplitCriticalEdges] = true;
   824         enabledTextIds[TraceLogger::RenumberBlocks] = true;
   825         enabledTextIds[TraceLogger::DominatorTree] = true;
   826         enabledTextIds[TraceLogger::PhiAnalysis] = true;
   827         enabledTextIds[TraceLogger::ApplyTypes] = true;
   828         enabledTextIds[TraceLogger::ParallelSafetyAnalysis] = true;
   829         enabledTextIds[TraceLogger::AliasAnalysis] = true;
   830         enabledTextIds[TraceLogger::GVN] = true;
   831         enabledTextIds[TraceLogger::UCE] = true;
   832         enabledTextIds[TraceLogger::LICM] = true;
   833         enabledTextIds[TraceLogger::RangeAnalysis] = true;
   834         enabledTextIds[TraceLogger::EffectiveAddressAnalysis] = true;
   835         enabledTextIds[TraceLogger::EliminateDeadCode] = true;
   836         enabledTextIds[TraceLogger::EdgeCaseAnalysis] = true;
   837         enabledTextIds[TraceLogger::EliminateRedundantChecks] = true;
   838     }
   840     const char *options = getenv("TLOPTIONS");
   841     if (options) {
   842         if (strstr(options, "help")) {
   843             fflush(nullptr);
   844             printf(
   845                 "\n"
   846                 "usage: TLOPTIONS=option,option,option,... where options can be:\n"
   847                 "\n"
   848                 "  DisableMainThread        Don't start logging the mainThread automatically.\n"
   849                 "  DisableOffThread         Don't start logging the off mainThread automatically.\n"
   850             );
   851             printf("\n");
   852             exit(0);
   853             /*NOTREACHED*/
   854         }
   856         if (strstr(options, "DisableMainThread"))
   857            mainThreadEnabled = false;
   858         if (strstr(options, "DisableOffThread"))
   859            offThreadEnabled = false;
   860     }
   862     startupTime = rdtsc();
   863     enabled = true;
   864     return true;
   865 }
   867 TraceLogger *
   868 js::TraceLoggerForMainThread(jit::CompileRuntime *runtime)
   869 {
   870     return traceLoggers.forMainThread(runtime);
   871 }
   873 TraceLogger *
   874 TraceLogging::forMainThread(jit::CompileRuntime *runtime)
   875 {
   876     return forMainThread(runtime->mainThread());
   877 }
   879 TraceLogger *
   880 js::TraceLoggerForMainThread(JSRuntime *runtime)
   881 {
   882     return traceLoggers.forMainThread(runtime);
   883 }
   885 TraceLogger *
   886 TraceLogging::forMainThread(JSRuntime *runtime)
   887 {
   888     return forMainThread(&runtime->mainThread);
   889 }
   891 TraceLogger *
   892 TraceLogging::forMainThread(PerThreadData *mainThread)
   893 {
   894     if (!mainThread->traceLogger) {
   895         AutoTraceLoggingLock lock(this);
   897         if (!lazyInit())
   898             return nullptr;
   900         TraceLogger *logger = create();
   901         mainThread->traceLogger = logger;
   903         if (!mainThreadLoggers.append(logger))
   904             return nullptr;
   906         if (!mainThreadEnabled)
   907             logger->disable();
   908     }
   910     return mainThread->traceLogger;
   911 }
   913 TraceLogger *
   914 js::TraceLoggerForCurrentThread()
   915 {
   916 #ifdef JS_THREADSAFE
   917     PRThread *thread = PR_GetCurrentThread();
   918     return traceLoggers.forThread(thread);
   919 #else
   920     MOZ_ASSUME_UNREACHABLE("No threads supported. Use TraceLoggerForMainThread for the main thread.");
   921 #endif // JS_THREADSAFE
   922 }
   924 #ifdef JS_THREADSAFE
   925 TraceLogger *
   926 TraceLogging::forThread(PRThread *thread)
   927 {
   928     AutoTraceLoggingLock lock(this);
   930     if (!lazyInit())
   931         return nullptr;
   933     ThreadLoggerHashMap::AddPtr p = threadLoggers.lookupForAdd(thread);
   934     if (p)
   935         return p->value();
   937     TraceLogger *logger = create();
   938     if (!logger)
   939         return nullptr;
   941     if (!threadLoggers.add(p, thread, logger)) {
   942         delete logger;
   943         return nullptr;
   944     }
   946     if (!offThreadEnabled)
   947         logger->disable();
   949     return logger;
   950 }
   951 #endif // JS_THREADSAFE
   953 TraceLogger *
   954 TraceLogging::create()
   955 {
   956     if (loggerId > 999) {
   957         fprintf(stderr, "TraceLogging: Can't create more than 999 different loggers.");
   958         return nullptr;
   959     }
   961     if (loggerId > 0) {
   962         int written = fprintf(out, ",\n");
   963         if (written < 0)
   964             fprintf(stderr, "TraceLogging: Error while writing.\n");
   965     }
   967     loggerId++;
   969     int written = fprintf(out, "{\"tree\":\"tl-tree.%d.tl\", \"events\":\"tl-event.%d.tl\", \"dict\":\"tl-dict.%d.json\", \"treeFormat\":\"64,64,31,1,32\"}",
   970                           loggerId, loggerId, loggerId);
   971     if (written < 0)
   972         fprintf(stderr, "TraceLogging: Error while writing.\n");
   975     TraceLogger *logger = new TraceLogger();
   976     if (!logger)
   977         return nullptr;
   979     if (!logger->init(loggerId)) {
   980         delete logger;
   981         return nullptr;
   982     }
   984     return logger;
   985 }
   987 bool
   988 js::TraceLogTextIdEnabled(uint32_t textId)
   989 {
   990     return traceLoggers.isTextIdEnabled(textId);
   991 }

mercurial