diff --git a/js/src/TraceLogging.cpp b/js/src/TraceLogging.cpp index 204245300aa..c062e3cd0c3 100644 --- a/js/src/TraceLogging.cpp +++ b/js/src/TraceLogging.cpp @@ -6,15 +6,13 @@ #include "TraceLogging.h" -#include -#include -#include -#include #include -#include +#include "jsapi.h" #include "jsscript.h" +#include "vm/Runtime.h" + using namespace js; #ifndef TRACE_LOG_DIR @@ -64,239 +62,465 @@ rdtsc(void) } #endif -const char* const TraceLogging::typeName[] = { - "1,s", // start script - "0,s", // stop script - "1,c", // start ion compilation - "0,c", // stop ion compilation - "1,r", // start regexp JIT execution - "0,r", // stop regexp JIT execution - "1,G", // start major GC - "0,G", // stop major GC - "1,g", // start minor GC - "0,g", // stop minor GC - "1,gS", // start GC sweeping - "0,gS", // stop GC sweeping - "1,gA", // start GC allocating - "0,gA", // stop GC allocating - "1,ps", // start script parsing - "0,ps", // stop script parsing - "1,pl", // start lazy parsing - "0,pl", // stop lazy parsing - "1,pf", // start Function parsing - "0,pf", // stop Function parsing - "e,i", // engine interpreter - "e,b", // engine baseline - "e,o" // engine ionmonkey -}; -TraceLogging* TraceLogging::loggers[] = {nullptr, nullptr, nullptr}; -bool TraceLogging::atexitSet = false; -uint64_t TraceLogging::startupTime = 0; +TraceLogging traceLoggers; -TraceLogging::TraceLogging(Logger id) - : nextTextId(1), - entries(nullptr), - curEntry(0), - numEntries(1000000), - fileno(0), - out(nullptr), - id(id) +// The text that will get logged for eagerly created logged text. +// When adding/removing something here, you must update the enum +// Tracelogger::TextId in TraceLogging.h too. +const char* const text[] = { + "TraceLogger failed to process text", + "Bailout", + "Baseline", + "GC", + "GCAllocating", + "GCSweeping", + "Interpreter", + "Invalidation", + "IonCompile", + "IonLink", + "IonMonkey", + "MinorGC", + "ParserCompileFunction", + "ParserCompileLazy", + "ParserCompileScript", + "TraceLogger", + "YarrCompile", + "YarrInterpret", + "YarrJIT" +}; + +TraceLogger::TraceLogger() + : enabled(false), + nextTextId(0), + top(nullptr) +{ } + +bool +TraceLogger::init(uint32_t loggerId) { - textMap.init(); + if (!pointerMap.init()) + return false; + if (!tree.init()) + return false; + if (!stack.init()) + return false; + if (!events.init()) + return false; + + JS_ASSERT(loggerId <= 999); + + char dictFilename[sizeof TRACE_LOG_DIR "tl-dict.100.json"]; + sprintf(dictFilename, TRACE_LOG_DIR "tl-dict.%d.json", loggerId); + dictFile = fopen(dictFilename, "w"); + if (!dictFile) + return false; + + char treeFilename[sizeof TRACE_LOG_DIR "tl-tree.100.tl"]; + sprintf(treeFilename, TRACE_LOG_DIR "tl-tree.%d.tl", loggerId); + treeFile = fopen(treeFilename, "wb"); + if (!treeFile) { + fclose(dictFile); + dictFile = nullptr; + return false; + } + + char eventFilename[sizeof TRACE_LOG_DIR "tl-event.100.tl"]; + sprintf(eventFilename, TRACE_LOG_DIR "tl-event.%d.tl", loggerId); + eventFile = fopen(eventFilename, "wb"); + if (!eventFile) { + fclose(dictFile); + fclose(treeFile); + dictFile = nullptr; + treeFile = nullptr; + return false; + } + + uint64_t start = rdtsc() - traceLoggers.startupTime; + + TreeEntry &treeEntry = tree.pushUninitialized(); + treeEntry.start = start; + treeEntry.stop = 0; + treeEntry.u.s.textId = 0; + treeEntry.u.s.hasChildren = false; + treeEntry.nextId = 0; + + StackEntry &stackEntry = stack.pushUninitialized(); + stackEntry.treeId = 0; + stackEntry.lastChildId = 0; + + int written = fprintf(dictFile, "["); + if (written < 0) + fprintf(stderr, "TraceLogging: Error while writing.\n"); + + // Eagerly create the default textIds, to match their Tracelogger::TextId. + for (uint32_t i = 0; i < LAST; i++) { + uint32_t textId = createTextId(text[i]); + JS_ASSERT(textId == i); + } + + enabled = true; + return true; +} + +TraceLogger::~TraceLogger() +{ + // Write dictionary to disk + if (dictFile) { + int written = fprintf(dictFile, "]"); + if (written < 0) + fprintf(stderr, "TraceLogging: Error while writing.\n"); + fclose(dictFile); + + dictFile = nullptr; + } + + // Write tree of logged events to disk. + if (treeFile) { + // Make sure every start entry has a corresponding stop value. + // We temporary enable logging for this. Stop doesn't need any extra data, + // so is safe to do, even when we encountered OOM. + enabled = true; + while (stack.size() > 0) + stopEvent(); + enabled = false; + + // Format data in big endian. + for (uint32_t i = 0; i < tree.size(); i++) { + tree[i].start = htobe64(tree[i].start); + tree[i].stop = htobe64(tree[i].stop); + tree[i].u.value = htobe32((tree[i].u.s.textId << 1) + tree[i].u.s.hasChildren); + tree[i].nextId = htobe32(tree[i].nextId); + } + + size_t bytesWritten = fwrite(tree.data(), sizeof(TreeEntry), tree.size(), treeFile); + if (bytesWritten < tree.size()) + fprintf(stderr, "TraceLogging: Couldn't write the full tree to disk.\n"); + tree.clear(); + fclose(treeFile); + + treeFile = nullptr; + } + + // Write details for all log entries to disk. + if (eventFile) { + // Format data in big endian + for (uint32_t i = 0; i < events.size(); i++) { + events[i].time = htobe64(events[i].time); + events[i].textId = htobe64(events[i].textId); + } + + size_t bytesWritten = fwrite(events.data(), sizeof(EventEntry), events.size(), eventFile); + if (bytesWritten < events.size()) + fprintf(stderr, "TraceLogging: Couldn't write all event entries to disk.\n"); + events.clear(); + fclose(eventFile); + + eventFile = nullptr; + } +} + +uint32_t +TraceLogger::createTextId(const char *text) +{ + assertNoQuotes(text); + + PointerHashMap::AddPtr p = pointerMap.lookupForAdd((const void *)text); + if (p) + return p->value(); + + uint32_t textId = nextTextId++; + if (!pointerMap.add(p, text, textId)) + return TraceLogger::TL_Error; + + int written; + if (textId > 0) + written = fprintf(dictFile, ",\n\"%s\"", text); + else + written = fprintf(dictFile, "\"%s\"", text); + + if (written < 0) + return TraceLogger::TL_Error; + + return textId; +} + +uint32_t +TraceLogger::createTextId(JSScript *script) +{ + assertNoQuotes(script->filename()); + + PointerHashMap::AddPtr p = pointerMap.lookupForAdd(script); + if (p) + return p->value(); + + uint32_t textId = nextTextId++; + if (!pointerMap.add(p, script, textId)) + return TraceLogger::TL_Error; + + int written; + if (textId > 0) { + written = fprintf(dictFile, ",\n\"script %s:%d:%d\"", script->filename(), + script->lineno(), script->column()); + } else { + written = fprintf(dictFile, "\"script %s:%d:%d\"", script->filename(), + script->lineno(), script->column()); + } + + if (written < 0) + return TraceLogger::TL_Error; + + return textId; +} + +uint32_t +TraceLogger::createTextId(const JS::ReadOnlyCompileOptions &compileOptions) +{ + assertNoQuotes(compileOptions.filename()); + + PointerHashMap::AddPtr p = pointerMap.lookupForAdd(&compileOptions); + if (p) + return p->value(); + + uint32_t textId = nextTextId++; + if (!pointerMap.add(p, &compileOptions, textId)) + return TraceLogger::TL_Error; + + int written; + if (textId > 0) { + written = fprintf(dictFile, ",\n\"script %s:%d:%d\"", compileOptions.filename(), + compileOptions.lineno, compileOptions.column); + } else { + written = fprintf(dictFile, "\"script %s:%d:%d\"", compileOptions.filename(), + compileOptions.lineno, compileOptions.column); + } + + if (written < 0) + return TraceLogger::TL_Error; + + return textId; +} + +void +TraceLogger::logTimestamp(uint32_t id) +{ + if (!enabled) + return; + + if (!events.ensureSpaceBeforeAdd()) { + fprintf(stderr, "TraceLogging: Disabled a tracelogger due to OOM.\n"); + enabled = false; + return; + } + + uint64_t time = rdtsc() - traceLoggers.startupTime; + + EventEntry &entry = events.pushUninitialized(); + entry.time = time; + entry.textId = id; +} + +void +TraceLogger::startEvent(uint32_t id) +{ + if (!enabled) + return; + + if (!tree.ensureSpaceBeforeAdd() || !stack.ensureSpaceBeforeAdd()) { + fprintf(stderr, "TraceLogging: Disabled a tracelogger due to OOM.\n"); + enabled = false; + return; + } + + uint64_t start = rdtsc() - traceLoggers.startupTime; + + // Patch up the tree to be correct. There are two scenarios: + // 1) Parent has no children yet. So update parent to include children. + // 2) Parent has already children. Update last child to link to the new + // child. + StackEntry &parent = stack.current(); + if (parent.lastChildId == 0) { + JS_ASSERT(tree[parent.treeId].u.s.hasChildren == 0); + JS_ASSERT(parent.treeId == tree.currentId()); + + tree[parent.treeId].u.s.hasChildren = 1; + } else { + JS_ASSERT(tree[parent.treeId].u.s.hasChildren == 1); + + tree[parent.lastChildId].nextId = tree.nextId(); + } + + // Add a new tree entry. + TreeEntry &treeEntry = tree.pushUninitialized(); + treeEntry.start = start; + treeEntry.stop = 0; + treeEntry.u.s.textId = id; + treeEntry.u.s.hasChildren = false; + treeEntry.nextId = 0; + + // Add a new stack entry. + StackEntry &stackEntry = stack.pushUninitialized(); + stackEntry.treeId = tree.currentId(); + stackEntry.lastChildId = 0; + + // Set the last child of the parent to this newly added entry. + parent.lastChildId = tree.currentId(); +} + +void +TraceLogger::stopEvent(uint32_t id) +{ + MOZ_ASSERT_IF(enabled, tree[stack.current().treeId].u.s.textId == id); + stopEvent(); +} + +void +TraceLogger::stopEvent() +{ + if (!enabled) + return; + + uint64_t stop = rdtsc() - traceLoggers.startupTime; + tree[stack.current().treeId].stop = stop; + stack.pop(); +} + +TraceLogging::TraceLogging() +{ + initialized = false; + enabled = false; + loggerId = 0; + +#ifdef JS_THREADSAFE + lock = PR_NewLock(); + if (!lock) + MOZ_CRASH(); +#endif } TraceLogging::~TraceLogging() { - if (entries) { - flush(); - js_free(entries); - entries = nullptr; - } - if (out) { + fprintf(out, "]"); fclose(out); out = nullptr; } -} -void -TraceLogging::grow() -{ - Entry* nentries = (Entry*) js_realloc(entries, numEntries*2*sizeof(Entry)); - - // Allocating a bigger array failed. - // Keep using the current storage, but remove all entries by flushing them. - if (!nentries) { - flush(); - return; - } - - entries = nentries; - numEntries *= 2; -} - -void -TraceLogging::log(Type type, const char* text /* = nullptr */, unsigned int number /* = 0 */) -{ - uint64_t now = rdtsc() - startupTime; - - // Create array containing the entries if not existing. - if (!entries) { - entries = (Entry*) js_malloc(numEntries*sizeof(Entry)); - if (!entries) - return; - } - - uint32_t textId = 0; - char *text_ = nullptr; - - if (text) { - TextHashMap::AddPtr p = textMap.lookupForAdd(text); - if (!p) { - // Copy the text, because original could already be freed before writing the log file. - text_ = strdup(text); - if (!text_) - return; - textId = nextTextId++; - if (!textMap.add(p, text, textId)) - return; - } else { - textId = p->value(); - } - } - - entries[curEntry++] = Entry(now, text_, textId, number, type); - - // Increase length when not enough place in the array - if (curEntry >= numEntries) - grow(); -} - -void -TraceLogging::log(Type type, const JS::ReadOnlyCompileOptions &options) -{ - this->log(type, options.filename(), options.lineno); -} - -void -TraceLogging::log(Type type, JSScript* script) -{ - this->log(type, script->filename(), script->lineno()); -} - -void -TraceLogging::log(const char* log) -{ - this->log(INFO, log, 0); -} - -void -TraceLogging::flush() -{ - // Open the logging file, when not opened yet. - if (!out) { - switch(id) { - case DEFAULT: - out = fopen(TRACE_LOG_DIR "tracelogging.log", "w"); - break; - case ION_BACKGROUND_COMPILER: - out = fopen(TRACE_LOG_DIR "tracelogging-compile.log", "w"); - break; - case GC_BACKGROUND: - out = fopen(TRACE_LOG_DIR "tracelogging-gc.log", "w"); - break; - default: - MOZ_ASSUME_UNREACHABLE("Bad trigger"); - return; - } - } - - // Print all log entries into the file - for (unsigned int i = 0; i < curEntry; i++) { - Entry entry = entries[i]; - int written; - if (entry.type() == INFO) { - written = fprintf(out, "I,%s\n", entry.text()); - } else { - if (entry.textId() > 0) { - if (entry.text()) { - written = fprintf(out, "%llu,%s,%s,%d\n", - (unsigned long long)entry.tick(), - typeName[entry.type()], - entry.text(), - entry.lineno()); - } else { - written = fprintf(out, "%llu,%s,%d,%d\n", - (unsigned long long)entry.tick(), - typeName[entry.type()], - entry.textId(), - entry.lineno()); - } - } else { - written = fprintf(out, "%llu,%s\n", - (unsigned long long)entry.tick(), - typeName[entry.type()]); - } + if (threadLoggers.initialized()) { + for (ThreadLoggerHashMap::Range r = threadLoggers.all(); !r.empty(); r.popFront()) { + delete r.front().value(); } - // A logging file can only be 2GB of length (fwrite limit). - if (written < 0) { - fprintf(stderr, "Writing tracelog to disk failed,"); - fprintf(stderr, "probably because the file would've exceeded the maximum size of 2GB"); - fclose(out); - exit(-1); - } - - if (entries[i].text() != nullptr) { - js_free(entries[i].text()); - entries[i].text_ = nullptr; - } - } - curEntry = 0; -} - -TraceLogging* -TraceLogging::getLogger(Logger id) -{ - if (!loggers[id]) { - loggers[id] = new TraceLogging(id); - if (!atexitSet) { - startupTime = rdtsc(); - atexit (releaseLoggers); - atexitSet = true; - } + threadLoggers.finish(); } - return loggers[id]; -} - -void -TraceLogging::releaseLoggers() -{ - for (size_t i = 0; i < LAST_LOGGER; i++) { - if (!loggers[i]) - continue; - - delete loggers[i]; - loggers[i] = nullptr; + if (lock) { + PR_DestroyLock(lock); + lock = nullptr; } + + enabled = false; } -/* Helper functions for asm calls */ -void -js::TraceLog(TraceLogging* logger, TraceLogging::Type type, JSScript* script) +bool +TraceLogging::lazyInit() { - logger->log(type, script); + if (initialized) + return enabled; + + initialized = true; + + out = fopen(TRACE_LOG_DIR "tl-data.json", "w"); + if (!out) + return false; + fprintf(out, "["); + + if (!threadLoggers.init()) + return false; + + startupTime = rdtsc(); + enabled = true; + return true; } -void -js::TraceLog(TraceLogging* logger, const char* log) +TraceLogger * +js::TraceLoggerForMainThread(JSRuntime *runtime) { - logger->log(log); + return traceLoggers.forMainThread(runtime); } -void -js::TraceLog(TraceLogging* logger, TraceLogging::Type type) +TraceLogger * +TraceLogging::forMainThread(JSRuntime *runtime) { - logger->log(type); + if (!runtime->mainThread.traceLogger) { + AutoTraceLoggingLock lock(this); + + if (!lazyInit()) + return nullptr; + + runtime->mainThread.traceLogger = create(); + } + + return runtime->mainThread.traceLogger; +} + +TraceLogger * +js::TraceLoggerForThread(PRThread *thread) +{ + return traceLoggers.forThread(thread); +} + +TraceLogger * +TraceLogging::forThread(PRThread *thread) +{ + AutoTraceLoggingLock lock(this); + + if (!lazyInit()) + return nullptr; + + ThreadLoggerHashMap::AddPtr p = threadLoggers.lookupForAdd(thread); + if (p) + return p->value(); + + TraceLogger *logger = create(); + if (!logger) + return nullptr; + + if (!threadLoggers.add(p, thread, logger)) { + delete logger; + return nullptr; + } + + return logger; +} + +TraceLogger * +TraceLogging::create() +{ + if (loggerId > 999) { + fprintf(stderr, "TraceLogging: Can't create more than 999 different loggers."); + return nullptr; + } + + if (loggerId > 0) { + int written = fprintf(out, ",\n"); + if (written < 0) + fprintf(stderr, "TraceLogging: Error while writing.\n"); + } + + + fprintf(out, "{\"tree\":\"tl-tree.%d.tl\", \"events\":\"tl-event.%d.tl\", \"dict\":\"tl-dict.%d.json\", \"treeFormat\":\"64,64,31,1,32\"}", + loggerId, loggerId, loggerId); + + loggerId++; + + TraceLogger *logger = new TraceLogger(); + if (!logger) + return nullptr; + + if (!logger->init(loggerId)) { + delete logger; + return nullptr; + } + + return logger; } diff --git a/js/src/TraceLogging.h b/js/src/TraceLogging.h index b5576180f8d..c8e3259ee89 100644 --- a/js/src/TraceLogging.h +++ b/js/src/TraceLogging.h @@ -7,157 +7,503 @@ #ifndef TraceLogging_h #define TraceLogging_h -#include -#include - #include "jsalloc.h" +#ifdef JS_THREADSAFE +# include "jslock.h" +#endif + +#include "mozilla/GuardObjects.h" #include "js/HashTable.h" #include "js/TypeDecls.h" +class PRThread; +struct JSRuntime; + namespace JS { -class ReadOnlyCompileOptions; + class ReadOnlyCompileOptions; } namespace js { -class TraceLogging -{ +/* + * Tracelogging overview. + * + * Tracelogging makes it possible to trace the timestamp of a single event and/or + * the duration of an event. This is implemented to give an as low overhead as + * possible so it doesn't interfere with running. + * + * The output of a tracelogging session is saved in /tmp/tl-data.json. + * The format of that file is a JS array per tracelogger (=thread), with a map + * containing: + * - dict: Name of the file containing a json table with the log text. + * All other files only contain a index to this table when logging. + * - events: Name of the file containing a flat list of log events saved + * in binary format. + * (64bit: Time Stamp Counter, 32bit index to dict) + * - tree: Name of the file containing the events with duration. The content + * is already in a tree data structure. This is also saved in a + * binary file. + * - treeFormat: The format used to encode the tree. By default "64,64,31,1,32". + * There are currently no other formats to save the tree. + * - 64,64,31,1,31 signifies how many bytes are used for the different + * parts of the tree. + * => 64 bits: Time Stamp Counter of start of event. + * => 64 bits: Time Stamp Counter of end of event. + * => 31 bits: Index to dict file containing the log text. + * => 1 bit: Boolean signifying if this entry has children. + * When true, the child can be found just behind this entry. + * => 32 bits: Containing the ID of the next event on the same depth + * or 0 if there isn't an event on the same depth anymore. + * + * /-> The position in the file. Id is this divided by size of entry. + * | So in this case this would be 1 (192bits per entry). + * | /-> Indicates there are children. The + * | | first child is located at current + * | | ID + 1. So 1 + 1 in this case: 2. + * | | Or 0x00180 in the tree file. + * | | /-> Next event on the same depth is + * | | | located at 4. So 0x00300 in the + * | | | tree file. + * 0x0000C0: [start, end, dictId, 1, 4] + * + * + * Example: + * 0x0: [start, end, dictId, 1, 0] + * | + * /----------------------------------\ + * | | + * 0xC0: [start, end, dictId, 0, 2] 0x180 [start, end, dictId, 1, 0] + * | + * /----------------------------------\ + * | | + * 0x240: [start, end, dictId, 0, 4] 0x300 [start, end, dictId, 0, 0] + * + * + * Logging something is done in 3 stages. + * 1) Get the tracelogger of the current thread. + * - TraceLoggerForMainThread(JSRuntime *) + * - TraceLoggerForThread(PR_GetCurrentThread()); + * 2) Optionally create a textId for the text that needs to get logged. This + * step takes some time, so try to do this beforehand, outside the hot + * path and don't do unnecessary repetitions, since it will criple + * performance. + * - TraceLogCreateTextId(logger, ...); + * + * There are also some text IDs created beforehand. They are located in + * Tracelogger::TextId. + * 3) Log the timestamp of an event: + * - TraceLogTimestamp(logger, textId); + * + * or the duration: + * - TraceLogStartEvent(logger, textId); + * - TraceLogStopEvent(logger, textId); + * + * or the duration with a RAII class: + * - AutoTraceLog logger(logger, textId); + */ + +class AutoTraceLog; + +template +class ContinuousSpace { + T *data_; + uint32_t next_; + uint32_t capacity_; + public: - enum Type { - SCRIPT_START, - SCRIPT_STOP, - ION_COMPILE_START, - ION_COMPILE_STOP, - YARR_JIT_START, - YARR_JIT_STOP, - GC_START, - GC_STOP, - MINOR_GC_START, - MINOR_GC_STOP, - GC_SWEEPING_START, - GC_SWEEPING_STOP, - GC_ALLOCATING_START, - GC_ALLOCATING_STOP, - PARSER_COMPILE_SCRIPT_START, - PARSER_COMPILE_SCRIPT_STOP, - PARSER_COMPILE_LAZY_START, - PARSER_COMPILE_LAZY_STOP, - PARSER_COMPILE_FUNCTION_START, - PARSER_COMPILE_FUNCTION_STOP, - INFO_ENGINE_INTERPRETER, - INFO_ENGINE_BASELINE, - INFO_ENGINE_IONMONKEY, - INFO - }; - enum Logger { - DEFAULT, - ION_BACKGROUND_COMPILER, - GC_BACKGROUND, + ContinuousSpace () + : data_(nullptr) + { } - LAST_LOGGER - }; + bool init() { + capacity_ = 64; + next_ = 0; + data_ = (T *) js_malloc(capacity_ * sizeof(T)); + if (!data_) + return false; - private: - struct Entry { - uint64_t tick_; - char* text_; - uint32_t textId_; - uint32_t lineno_; - uint8_t type_; - - Entry(uint64_t tick, char* text, uint32_t textId, uint32_t lineno, Type type) - : tick_(tick), - text_(text), - textId_(textId), - lineno_(lineno), - type_((uint8_t)type) {} - - uint64_t tick() const { return tick_; } - char *text() const { return text_; } - uint32_t textId() const { return textId_; } - uint32_t lineno() const { return lineno_; } - Type type() const { return (Type) type_; } - }; - - typedef HashMap, - SystemAllocPolicy> TextHashMap; - - TextHashMap textMap; - uint32_t nextTextId; - Entry *entries; - unsigned int curEntry; - unsigned int numEntries; - int fileno; - FILE *out; - Logger id; - - static bool atexitSet; - static const char * const typeName[]; - static TraceLogging* loggers[]; - static uint64_t startupTime; - public: - TraceLogging(Logger id); - ~TraceLogging(); - - void log(Type type, const char* text = nullptr, unsigned int number = 0); - void log(Type type, const JS::ReadOnlyCompileOptions &options); - void log(Type type, JSScript* script); - void log(const char* log); - void flush(); - - static TraceLogging* getLogger(Logger id); - static TraceLogging* defaultLogger() { - return getLogger(DEFAULT); + return true; } - static void releaseLoggers(); - private: - void grow(); + T *data() { + return data_; + } + + uint32_t capacity() { + return capacity_; + } + + uint32_t size() { + return next_; + } + + uint32_t nextId() { + return next_; + } + + T &next() { + return data()[next_]; + } + + uint32_t currentId() { + JS_ASSERT(next_ > 0); + return next_ - 1; + } + + T ¤t() { + return data()[currentId()]; + } + + bool ensureSpaceBeforeAdd() { + if (next_ < capacity_) + return true; + + uint32_t nCapacity = capacity_ * 2; + T *entries = (T *) js_realloc(data_, nCapacity * sizeof(T)); + + if (!entries) + return false; + + data_ = entries; + capacity_ = nCapacity; + + return true; + } + + T &operator[](size_t i) { + MOZ_ASSERT(i < next_); + return data()[i]; + } + + void push(T &data) { + MOZ_ASSERT(next_ < capacity_); + data()[next_++] = data; + } + + T &pushUninitialized() { + return data()[next_++]; + } + + void pop() { + JS_ASSERT(next_ > 0); + next_--; + } + + void clear() { + next_ = 0; + } }; -/* Helpers functions for asm calls */ -void TraceLog(TraceLogging* logger, TraceLogging::Type type, JSScript* script); -void TraceLog(TraceLogging* logger, const char* log); -void TraceLog(TraceLogging* logger, TraceLogging::Type type); +class TraceLogger +{ + public: + // Predefined IDs for common operations. These IDs can be used + // without using TraceLogCreateTextId, because there are already created. + // When changing the enum here, you must update the array containing the + // actual logged text in TraceLogging.cpp. + enum TextId { + TL_Error, + Bailout, + Baseline, + GC, + GCAllocating, + GCSweeping, + Interpreter, + Invalidation, + IonCompile, + IonLink, + IonMonkey, + MinorGC, + ParserCompileFunction, + ParserCompileLazy, + ParserCompileScript, + TL, + YarrCompile, + YarrInterpret, + YarrJIT, -/* Automatic logging at the start and end of function call */ -class AutoTraceLog { - TraceLogging* logger; - TraceLogging::Type stop; + LAST + }; + +#ifdef JS_TRACE_LOGGING + private: + typedef HashMap, + SystemAllocPolicy> PointerHashMap; + + // The layout of the tree in memory and in the log file. Readable by JS + // using TypedArrays. + struct TreeEntry { + uint64_t start; + uint64_t stop; + union { + struct { + uint32_t textId: 31; + uint32_t hasChildren: 1; + } s; + uint32_t value; + } u; + uint32_t nextId; + + TreeEntry(uint64_t start, uint64_t stop, uint32_t textId, bool hasChildren, + uint32_t nextId) + { + this->start = start; + this->stop = stop; + this->u.s.textId = textId; + this->u.s.hasChildren = hasChildren; + this->nextId = nextId; + } + }; + + // Helper structure for keeping track of the currently active entries in + // the tree. Pushed by `start(id)`, popped by `stop(id)`. + struct StackEntry { + uint32_t treeId; + uint32_t lastChildId; + StackEntry(uint32_t treeId, uint32_t lastChildId) + : treeId(treeId), lastChildId(lastChildId) + { } + }; + + // The layout of the event log in memory and in the log file. + // Readable by JS using TypedArrays. + struct EventEntry { + uint64_t time; + uint32_t textId; + EventEntry(uint64_t time, uint32_t textId) + : time(time), textId(textId) + { } + }; + + FILE *dictFile; + FILE *treeFile; + FILE *eventFile; + + bool enabled; + uint32_t nextTextId; + + PointerHashMap pointerMap; + + ContinuousSpace tree; + ContinuousSpace stack; + ContinuousSpace events; + + uint32_t treeOffset; public: - AutoTraceLog(TraceLogging* logger, TraceLogging::Type start, TraceLogging::Type stop, - const JS::ReadOnlyCompileOptions &options) - : logger(logger), - stop(stop) - { - logger->log(start, options); - } + AutoTraceLog *top; - AutoTraceLog(TraceLogging* logger, TraceLogging::Type start, TraceLogging::Type stop, - JSScript* script) - : logger(logger), - stop(stop) - { - logger->log(start, script); - } + private: + void updateHasChildren(uint32_t treeId, bool hasChildren = false); + void updateNextId(uint32_t treeId, bool nextId); + void updateStop(uint32_t treeId, uint64_t timestamp); + void flush(); - AutoTraceLog(TraceLogging* logger, TraceLogging::Type start, TraceLogging::Type stop) + public: + TraceLogger(); + ~TraceLogger(); + + bool init(uint32_t loggerId); + + // The createTextId functions map a unique input to a logger ID. + // This ID can be used to log something. Calls to these functions should be + // limited if possible, because of the overhead. + uint32_t createTextId(const char *text); + uint32_t createTextId(JSScript *script); + uint32_t createTextId(const JS::ReadOnlyCompileOptions &script); + + // Log an event (no start/stop, only the timestamp is recorded). + void logTimestamp(uint32_t id); + + // Record timestamps for start and stop of an event. + // In the stop method, the ID is only used in debug builds to test + // correctness. + void startEvent(uint32_t id); + void stopEvent(uint32_t id); + void stopEvent(); + + private: + void assertNoQuotes(const char *text) { +#ifdef DEBUG + const char *quote = strchr(text, '"'); + MOZ_ASSERT(!quote); +#endif + } +#endif +}; + +class TraceLogging +{ +#ifdef JS_TRACE_LOGGING + typedef HashMap, + SystemAllocPolicy> ThreadLoggerHashMap; + + bool initialized; + bool enabled; + ThreadLoggerHashMap threadLoggers; + uint32_t loggerId; + FILE *out; + + public: + uint64_t startupTime; +#ifdef JS_THREADSAFE + PRLock *lock; +#endif + + TraceLogging(); + ~TraceLogging(); + + TraceLogger *forMainThread(JSRuntime *runtime); + TraceLogger *forThread(PRThread *thread); + + private: + TraceLogger *create(); + bool lazyInit(); +#endif +}; + +#ifdef JS_TRACE_LOGGING +TraceLogger *TraceLoggerForMainThread(JSRuntime *runtime); +TraceLogger *TraceLoggerForThread(PRThread *thread); +#else +inline TraceLogger *TraceLoggerForMainThread(JSRuntime *runtime) { + return nullptr; +}; +inline TraceLogger *TraceLoggerForThread(PRThread *thread) { + return nullptr; +}; +#endif + +inline uint32_t TraceLogCreateTextId(TraceLogger *logger, JSScript *script) { +#ifdef JS_TRACE_LOGGING + if (logger) + return logger->createTextId(script); +#endif + return TraceLogger::TL_Error; +} +inline uint32_t TraceLogCreateTextId(TraceLogger *logger, + const JS::ReadOnlyCompileOptions &compileOptions) +{ +#ifdef JS_TRACE_LOGGING + if (logger) + return logger->createTextId(compileOptions); +#endif + return TraceLogger::TL_Error; +} +inline uint32_t TraceLogCreateTextId(TraceLogger *logger, const char *text) { +#ifdef JS_TRACE_LOGGING + if (logger) + return logger->createTextId(text); +#endif + return TraceLogger::TL_Error; +} +inline void TraceLogTimestamp(TraceLogger *logger, uint32_t textId) { +#ifdef JS_TRACE_LOGGING + if (logger) + logger->logTimestamp(textId); +#endif +} +inline void TraceLogStartEvent(TraceLogger *logger, uint32_t textId) { +#ifdef JS_TRACE_LOGGING + if (logger) + logger->startEvent(textId); +#endif +} +inline void TraceLogStopEvent(TraceLogger *logger, uint32_t textId) { +#ifdef JS_TRACE_LOGGING + if (logger) + logger->stopEvent(textId); +#endif +} +inline void TraceLogStopEvent(TraceLogger *logger) { +#ifdef JS_TRACE_LOGGING + if (logger) + logger->stopEvent(); +#endif +} + +// Automatic logging at the start and end of function call. +class AutoTraceLog { +#ifdef JS_TRACE_LOGGING + TraceLogger *logger; + uint32_t textId; + bool executed; + AutoTraceLog *prev; + + public: + AutoTraceLog(TraceLogger *logger, uint32_t textId MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : logger(logger), - stop(stop) + textId(textId), + executed(false) { - logger->log(start); + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + if (logger) { + TraceLogStartEvent(logger, textId); + + prev = logger->top; + logger->top = this; + } } ~AutoTraceLog() { - logger->log(stop); + if (logger) { + while (this != logger->top) + logger->top->stop(); + stop(); + } } + private: + void stop() { + if (!executed) { + executed = true; + TraceLogStopEvent(logger, textId); + } + + if (logger->top == this) + logger->top = prev; + } +#else + public: + AutoTraceLog(TraceLogger *logger, uint32_t textId MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } +#endif + + private: + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; -} /* namespace js */ +#ifdef JS_TRACE_LOGGING +class AutoTraceLoggingLock +{ + TraceLogging *logging; + + public: + AutoTraceLoggingLock(TraceLogging *logging MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : logging(logging) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; +#ifdef JS_THREADSAFE + PR_Lock(logging->lock); +#endif + } + ~AutoTraceLoggingLock() { +#ifdef JS_THREADSAFE + PR_Unlock(logging->lock); +#endif + } + private: + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; +#endif + +} /* namedata js */ #endif /* TraceLogging_h */ diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 3556691c748..9e5723ccb09 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -8,6 +8,7 @@ #include "jscntxt.h" #include "jsscript.h" +#include "TraceLogging.h" #include "frontend/BytecodeEmitter.h" #include "frontend/FoldConstants.h" @@ -189,12 +190,14 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco { RootedString source(cx, source_); -#if JS_TRACE_LOGGING - js::AutoTraceLog logger(js::TraceLogging::defaultLogger(), - js::TraceLogging::PARSER_COMPILE_SCRIPT_START, - js::TraceLogging::PARSER_COMPILE_SCRIPT_STOP, - options); -#endif + js::TraceLogger *logger = nullptr; + if (cx->isJSContext()) + logger = TraceLoggerForMainThread(cx->asJSContext()->runtime()); + else + logger = TraceLoggerForThread(PR_GetCurrentThread()); + uint32_t logId = js::TraceLogCreateTextId(logger, options); + js::AutoTraceLog scriptLogger(logger, logId); + js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileScript); if (cx->isJSContext()) MaybeCallSourceHandler(cx->asJSContext(), options, chars, length); @@ -437,12 +440,10 @@ frontend::CompileLazyFunction(JSContext *cx, Handle lazy, const jsc .setNoScriptRval(false) .setSelfHostingMode(false); -#if JS_TRACE_LOGGING - js::AutoTraceLog logger(js::TraceLogging::defaultLogger(), - js::TraceLogging::PARSER_COMPILE_LAZY_START, - js::TraceLogging::PARSER_COMPILE_LAZY_STOP, - options); -#endif + js::TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime()); + uint32_t logId = js::TraceLogCreateTextId(logger, options); + js::AutoTraceLog scriptLogger(logger, logId); + js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileLazy); Parser parser(cx, &cx->tempLifoAlloc(), options, chars, length, /* foldConstants = */ true, nullptr, lazy); @@ -497,12 +498,10 @@ CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyComp const AutoNameVector &formals, const jschar *chars, size_t length, GeneratorKind generatorKind) { -#if JS_TRACE_LOGGING - js::AutoTraceLog logger(js::TraceLogging::defaultLogger(), - js::TraceLogging::PARSER_COMPILE_FUNCTION_START, - js::TraceLogging::PARSER_COMPILE_FUNCTION_STOP, - options); -#endif + js::TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime()); + uint32_t logId = js::TraceLogCreateTextId(logger, options); + js::AutoTraceLog scriptLogger(logger, logId); + js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileFunction); // FIXME: make Function pass in two strings and parse them as arguments and // ProgramElements respectively. diff --git a/js/src/jit/Bailouts.cpp b/js/src/jit/Bailouts.cpp index f8ee8402bf0..2fe639fb125 100644 --- a/js/src/jit/Bailouts.cpp +++ b/js/src/jit/Bailouts.cpp @@ -7,6 +7,7 @@ #include "jit/Bailouts.h" #include "jscntxt.h" +#include "TraceLogging.h" #include "jit/BaselineJIT.h" #include "jit/Ion.h" @@ -78,6 +79,9 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo) IonBailoutIterator iter(jitActivations, sp); JitActivation *activation = jitActivations.activation()->asJit(); + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); + TraceLogTimestamp(logger, TraceLogger::Bailout); + IonSpew(IonSpew_Bailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset()); JS_ASSERT(IsBaselineEnabled(cx)); @@ -109,6 +113,9 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut, IonBailoutIterator iter(jitActivations, sp); JitActivation *activation = jitActivations.activation()->asJit(); + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); + TraceLogTimestamp(logger, TraceLogger::Invalidation); + IonSpew(IonSpew_Bailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset()); // Note: the frame size must be computed before we return from this function. diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 8efc683abe9..6db53314042 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -1261,9 +1261,9 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt JS_ASSERT(bailoutInfo != nullptr); JS_ASSERT(*bailoutInfo == nullptr); -#if JS_TRACE_LOGGING - TraceLogging::defaultLogger()->log(TraceLogging::INFO_ENGINE_BASELINE); -#endif + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); + TraceLogStopEvent(logger, TraceLogger::IonMonkey); + TraceLogStartEvent(logger, TraceLogger::Baseline); // The caller of the top frame must be one of the following: // IonJS - Ion calling into Ion. @@ -1351,12 +1351,11 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt while (true) { MOZ_ASSERT(snapIter.instruction()->isResumePoint()); -#if JS_TRACE_LOGGING if (frameNo > 0) { - TraceLogging::defaultLogger()->log(TraceLogging::SCRIPT_START, scr); - TraceLogging::defaultLogger()->log(TraceLogging::INFO_ENGINE_BASELINE); + TraceLogStartEvent(logger, TraceLogCreateTextId(logger, scr)); + TraceLogStartEvent(logger, TraceLogger::Baseline); } -#endif + IonSpew(IonSpew_BaselineBailouts, " FrameNo %d", frameNo); // If we are bailing out to a catch or finally block in this frame, diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 87ee96dd6f4..a5fd022db57 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -345,8 +345,13 @@ BaselineCompiler::emitPrologue() masm.bind(&earlyStackCheckFailed); #if JS_TRACE_LOGGING - masm.tracelogStart(script.get()); - masm.tracelogLog(TraceLogging::INFO_ENGINE_BASELINE); + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); + Register loggerReg = RegisterSet::Volatile().takeGeneral(); + masm.Push(loggerReg); + masm.movePtr(ImmPtr(logger), loggerReg); + masm.tracelogStart(loggerReg, TraceLogCreateTextId(logger, script.get())); + masm.tracelogStart(loggerReg, TraceLogger::Baseline); + masm.Pop(loggerReg); #endif // Record the offset of the prologue, because Ion can bailout before @@ -382,7 +387,15 @@ BaselineCompiler::emitEpilogue() masm.bind(&return_); #if JS_TRACE_LOGGING - masm.tracelogStop(); + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); + Register loggerReg = RegisterSet::Volatile().takeGeneral(); + masm.Push(loggerReg); + masm.movePtr(ImmPtr(logger), loggerReg); + masm.tracelogStop(loggerReg, TraceLogger::Baseline); + // Stop the script. Using a stop without checking the textId, since we + // we didn't save the textId for the script. + masm.tracelogStop(loggerReg); + masm.Pop(loggerReg); #endif // Pop SPS frame if necessary diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index 0e7776d374c..c5c86fba683 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -200,9 +200,9 @@ jit::EnterBaselineAtBranch(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc) data.calleeToken = CalleeToToken(fp->script()); } -#if JS_TRACE_LOGGING - TraceLogging::defaultLogger()->log(TraceLogging::INFO_ENGINE_BASELINE); -#endif + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); + TraceLogStopEvent(logger, TraceLogger::Interpreter); + TraceLogStartEvent(logger, TraceLogger::Baseline); IonExecStatus status = EnterBaseline(cx, data); if (status != IonExec_Ok) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 52eccfa2ae5..5056a18120e 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1288,7 +1288,12 @@ CodeGenerator::visitOsrEntry(LOsrEntry *lir) setOsrEntryOffset(masm.size()); #if JS_TRACE_LOGGING - masm.tracelogLog(TraceLogging::INFO_ENGINE_IONMONKEY); + if (gen->info().executionMode() == SequentialExecution) { + if (!emitTracelogStopEvent(TraceLogger::Baseline)) + return false; + if (!emitTracelogStartEvent(TraceLogger::IonMonkey)) + return false; + } #endif // Allocate the full frame for this function. @@ -6249,8 +6254,12 @@ CodeGenerator::generate() return false; #if JS_TRACE_LOGGING - masm.tracelogStart(gen->info().script()); - masm.tracelogLog(TraceLogging::INFO_ENGINE_IONMONKEY); + if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) { + if (!emitTracelogScriptStart()) + return false; + if (!emitTracelogStartEvent(TraceLogger::IonMonkey)) + return false; + } #endif // Before generating any code, we generate type checks for all parameters. @@ -6275,8 +6284,12 @@ CodeGenerator::generate() setSkipArgCheckEntryOffset(masm.size()); #if JS_TRACE_LOGGING - masm.tracelogStart(gen->info().script()); - masm.tracelogLog(TraceLogging::INFO_ENGINE_IONMONKEY); + if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) { + if (!emitTracelogScriptStart()) + return false; + if (!emitTracelogStartEvent(TraceLogger::IonMonkey)) + return false; + } masm.bind(&skip); #endif @@ -6469,6 +6482,23 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints) if (patchableBackedges_.length() > 0) ionScript->copyPatchableBackedges(cx, code, patchableBackedges_.begin()); +#if JS_TRACE_LOGGING + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); + for (uint32_t i = 0; i < patchableTraceLoggers_.length(); i++) { + patchableTraceLoggers_[i].fixup(&masm); + Assembler::patchDataWithValueCheck(CodeLocationLabel(code, patchableTraceLoggers_[i]), + ImmPtr(logger), + ImmPtr(nullptr)); + } + uint32_t scriptId = TraceLogCreateTextId(logger, script); + for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) { + patchableTLScripts_[i].fixup(&masm); + Assembler::patchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]), + ImmPtr((void *)scriptId), + ImmPtr((void *)0)); + } +#endif + switch (executionMode) { case SequentialExecution: // The correct state for prebarriers is unknown until the end of compilation, diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 0d0b2025ce9..3bac8cde28d 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -11,9 +11,7 @@ #include "jscompartment.h" #include "jsworkers.h" -#if JS_TRACE_LOGGING #include "TraceLogging.h" -#endif #include "jsprf.h" #include "gc/Marking.h" @@ -1635,6 +1633,8 @@ AttachFinishedCompilations(JSContext *cx) GlobalWorkerThreadState::IonBuilderVector &finished = WorkerThreadState().ionFinishedList(); + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); + // Incorporate any off thread compilations for the compartment which have // finished, failed or have been cancelled. while (true) { @@ -1655,6 +1655,8 @@ AttachFinishedCompilations(JSContext *cx) if (CodeGenerator *codegen = builder->backgroundCodegen()) { RootedScript script(cx, builder->script()); IonContext ictx(cx, &builder->alloc()); + AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script)); + AutoTraceLog logLink(logger, TraceLogger::IonLink); // Root the assembler until the builder is finished below. As it // was constructed off thread, the assembler has not been rooted @@ -1748,12 +1750,10 @@ IonCompile(JSContext *cx, JSScript *script, ExecutionMode executionMode, bool recompile, OptimizationLevel optimizationLevel) { -#if JS_TRACE_LOGGING - AutoTraceLog logger(TraceLogging::defaultLogger(), - TraceLogging::ION_COMPILE_START, - TraceLogging::ION_COMPILE_STOP, - script); -#endif + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); + AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script)); + AutoTraceLog logCompile(logger, TraceLogger::IonCompile); + JS_ASSERT(optimizationLevel > Optimization_DontCompile); // Make sure the script's canonical function isn't lazy. We can't de-lazify diff --git a/js/src/jit/IonMacroAssembler.cpp b/js/src/jit/IonMacroAssembler.cpp index 8c3243307f9..b905aa12699 100644 --- a/js/src/jit/IonMacroAssembler.cpp +++ b/js/src/jit/IonMacroAssembler.cpp @@ -1138,66 +1138,116 @@ MacroAssembler::printf(const char *output, Register value) #if JS_TRACE_LOGGING void -MacroAssembler::tracelogStart(JSScript *script) +MacroAssembler::tracelogStart(Register logger, uint32_t textId) { - void (&TraceLogStart)(TraceLogging*, TraceLogging::Type, JSScript*) = TraceLog; + void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStartEvent; + + PushRegsInMask(RegisterSet::Volatile()); + RegisterSet regs = RegisterSet::Volatile(); - PushRegsInMask(regs); + regs.takeUnchecked(logger); Register temp = regs.takeGeneral(); - Register type = regs.takeGeneral(); - Register rscript = regs.takeGeneral(); - setupUnalignedABICall(3, temp); - movePtr(ImmPtr(TraceLogging::defaultLogger()), temp); + setupUnalignedABICall(2, temp); + passABIArg(logger); + move32(Imm32(textId), temp); passABIArg(temp); - move32(Imm32(TraceLogging::SCRIPT_START), type); - passABIArg(type); - movePtr(ImmGCPtr(script), rscript); - passABIArg(rscript); - callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStart)); + callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc)); PopRegsInMask(RegisterSet::Volatile()); } void -MacroAssembler::tracelogStop() +MacroAssembler::tracelogStart(Register logger, Register textId) { - void (&TraceLogStop)(TraceLogging*, TraceLogging::Type) = TraceLog; + void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStartEvent; + + PushRegsInMask(RegisterSet::Volatile()); + RegisterSet regs = RegisterSet::Volatile(); - PushRegsInMask(regs); + regs.takeUnchecked(logger); + regs.takeUnchecked(textId); Register temp = regs.takeGeneral(); - Register logger = regs.takeGeneral(); - Register type = regs.takeGeneral(); setupUnalignedABICall(2, temp); - movePtr(ImmPtr(TraceLogging::defaultLogger()), logger); passABIArg(logger); - move32(Imm32(TraceLogging::SCRIPT_STOP), type); - passABIArg(type); - callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStop)); + passABIArg(textId); + callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc)); + + regs.add(temp); PopRegsInMask(RegisterSet::Volatile()); } void -MacroAssembler::tracelogLog(TraceLogging::Type type) +MacroAssembler::tracelogStop(Register logger, uint32_t textId) { - void (&TraceLogStop)(TraceLogging*, TraceLogging::Type) = TraceLog; + void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStopEvent; + + PushRegsInMask(RegisterSet::Volatile()); + RegisterSet regs = RegisterSet::Volatile(); - PushRegsInMask(regs); + regs.takeUnchecked(logger); Register temp = regs.takeGeneral(); - Register logger = regs.takeGeneral(); - Register rtype = regs.takeGeneral(); setupUnalignedABICall(2, temp); - movePtr(ImmPtr(TraceLogging::defaultLogger()), logger); passABIArg(logger); - move32(Imm32(type), rtype); - passABIArg(rtype); - callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStop)); + move32(Imm32(textId), temp); + passABIArg(temp); + callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc)); + + regs.add(temp); + + PopRegsInMask(RegisterSet::Volatile()); +} + +void +MacroAssembler::tracelogStop(Register logger, Register textId) +{ +#ifdef DEBUG + void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStopEvent; + + PushRegsInMask(RegisterSet::Volatile()); + + RegisterSet regs = RegisterSet::Volatile(); + regs.takeUnchecked(logger); + regs.takeUnchecked(textId); + + Register temp = regs.takeGeneral(); + + setupUnalignedABICall(2, temp); + passABIArg(logger); + passABIArg(textId); + callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc)); + + regs.add(temp); + + PopRegsInMask(RegisterSet::Volatile()); +#else + tracelogStop(logger); +#endif +} + +void +MacroAssembler::tracelogStop(Register logger) +{ + void (&TraceLogFunc)(TraceLogger*) = TraceLogStopEvent; + + PushRegsInMask(RegisterSet::Volatile()); + + RegisterSet regs = RegisterSet::Volatile(); + regs.takeUnchecked(logger); + + Register temp = regs.takeGeneral(); + + setupUnalignedABICall(1, temp); + passABIArg(logger); + callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc)); + + regs.add(temp); PopRegsInMask(RegisterSet::Volatile()); } diff --git a/js/src/jit/IonMacroAssembler.h b/js/src/jit/IonMacroAssembler.h index 8f59c636c19..c9c461d931a 100644 --- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -10,6 +10,7 @@ #ifdef JS_ION #include "jscompartment.h" +#include "TraceLogging.h" #if defined(JS_CODEGEN_X86) # include "jit/x86/MacroAssembler-x86.h" @@ -1123,9 +1124,11 @@ class MacroAssembler : public MacroAssemblerSpecific void printf(const char *output, Register value); #if JS_TRACE_LOGGING - void tracelogStart(JSScript *script); - void tracelogStop(); - void tracelogLog(TraceLogging::Type type); + void tracelogStart(Register logger, uint32_t textId); + void tracelogStart(Register logger, Register textId); + void tracelogStop(Register logger, uint32_t textId); + void tracelogStop(Register logger, Register textId); + void tracelogStop(Register logger); #endif #define DISPATCH_FLOATING_POINT_OP(method, type, arg1d, arg1f, arg2) \ diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index 8b6290c1dd5..36921a3aece 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -56,9 +56,16 @@ bool CodeGeneratorARM::generateEpilogue() { masm.bind(&returnLabel_); + #if JS_TRACE_LOGGING - masm.tracelogStop(); + if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) { + if (!emitTracelogStopEvent(TraceLogger::IonMonkey)) + return false; + if (!emitTracelogScriptStop()) + return false; + } #endif + if (gen->compilingAsmJS()) { // Pop the stack we allocated at the start of the function. masm.freeStack(frameDepth_); diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 3248f88ae3c..adad7887cc2 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -995,5 +995,75 @@ CodeGeneratorShared::addCacheLocations(const CacheLocationList &locs, size_t *nu return firstIndex; } +#if JS_TRACE_LOGGING + +bool +CodeGeneratorShared::emitTracelogScript(bool isStart) +{ + RegisterSet regs = RegisterSet::Volatile(); + Register logger = regs.takeGeneral(); + Register script = regs.takeGeneral(); + + masm.Push(logger); + masm.Push(script); + + CodeOffsetLabel patchLogger = masm.movWithPatch(ImmPtr(nullptr), logger); + if (!patchableTraceLoggers_.append(patchLogger)) + return false; + + CodeOffsetLabel patchScript = masm.movWithPatch(ImmWord(0), script); + if (!patchableTLScripts_.append(patchScript)) + return false; + + if (isStart) + masm.tracelogStart(logger, script); + else + masm.tracelogStop(logger, script); + + masm.Pop(script); + masm.Pop(logger); + return true; +} + +bool +CodeGeneratorShared::emitTracelogTree(bool isStart, uint32_t textId) +{ + RegisterSet regs = RegisterSet::Volatile(); + Register logger = regs.takeGeneral(); + + masm.Push(logger); + + CodeOffsetLabel patchLocation = masm.movWithPatch(ImmPtr(nullptr), logger); + if (!patchableTraceLoggers_.append(patchLocation)) + return false; + + if (isStart) + masm.tracelogStart(logger, textId); + else + masm.tracelogStop(logger, textId); + + masm.Pop(logger); + return true; +} + +bool +CodeGeneratorShared::emitTracelogStopEvent() +{ + RegisterSet regs = RegisterSet::Volatile(); + Register logger = regs.takeGeneral(); + + masm.Push(logger); + + CodeOffsetLabel patchLocation = masm.movWithPatch(ImmPtr(nullptr), logger); + if (!patchableTraceLoggers_.append(patchLocation)) + return false; + + masm.tracelogStop(logger); + + masm.Pop(logger); + return true; +} +#endif + } // namespace jit } // namespace js diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index a603ae3f807..212ce907105 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -89,6 +89,11 @@ class CodeGeneratorShared : public LInstructionVisitor // Patchable backedges generated for loops. Vector patchableBackedges_; +#if JS_TRACE_LOGGING + js::Vector patchableTraceLoggers_; + js::Vector patchableTLScripts_; +#endif + // When profiling is enabled, this is the instrumentation manager which // maintains state of what script is currently being generated (for inline // scripts) and when instrumentation needs to be emitted or skipped. @@ -443,6 +448,31 @@ class CodeGeneratorShared : public LInstructionVisitor OutOfLinePropagateAbortPar *oolPropagateAbortPar(LInstruction *lir); virtual bool visitOutOfLineAbortPar(OutOfLineAbortPar *ool) = 0; virtual bool visitOutOfLinePropagateAbortPar(OutOfLinePropagateAbortPar *ool) = 0; + +#if JS_TRACE_LOGGING + protected: + bool emitTracelogScript(bool isStart); + bool emitTracelogTree(bool isStart, uint32_t textId); + + public: + bool emitTracelogScriptStart() { + return emitTracelogScript(/* isStart =*/ true); + } + bool emitTracelogScriptStop() { + return emitTracelogScript(/* isStart =*/ false); + } + bool emitTracelogStartEvent(uint32_t textId) { + return emitTracelogTree(/* isStart =*/ true, textId); + } + bool emitTracelogStopEvent(uint32_t textId) { +#ifdef DEBUG + return emitTracelogTree(/* isStart =*/ false, textId); +#else + return emitTracelogScript(/* isStart =*/ false); +#endif + } + bool emitTracelogStopEvent(); +#endif }; // An out-of-line path is generated at the end of the function. diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.cpp b/js/src/jit/shared/CodeGenerator-x86-shared.cpp index e812f7779d5..409527a637d 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp @@ -49,7 +49,12 @@ CodeGeneratorX86Shared::generateEpilogue() masm.bind(&returnLabel_); #if JS_TRACE_LOGGING - masm.tracelogStop(); + if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) { + if (!emitTracelogStopEvent(TraceLogger::IonMonkey)) + return false; + if (!emitTracelogScriptStop()) + return false; + } #endif // Pop the stack we allocated at the start of the function. diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 21af761c544..cbaf0cf535c 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -197,9 +197,7 @@ # include "jswin.h" #endif #include "prmjtime.h" -#if JS_TRACE_LOGGING #include "TraceLogging.h" -#endif #include "gc/FindSCCs.h" #include "gc/GCInternals.h" @@ -2558,9 +2556,7 @@ GCHelperThread::threadLoop() { AutoLockGC lock(rt); -#if JS_TRACE_LOGGING - TraceLogging *logger = TraceLogging::getLogger(TraceLogging::GC_BACKGROUND); -#endif + TraceLogger *logger = TraceLoggerForThread(PR_GetCurrentThread()); /* * Even on the first iteration the state can be SHUTDOWN or SWEEPING if @@ -2574,22 +2570,16 @@ GCHelperThread::threadLoop() case IDLE: wait(wakeup); break; - case SWEEPING: -#if JS_TRACE_LOGGING - logger->log(TraceLogging::GC_SWEEPING_START); -#endif + case SWEEPING: { + AutoTraceLog logSweeping(logger, TraceLogger::GCSweeping); doSweep(); if (state == SWEEPING) state = IDLE; PR_NotifyAllCondVar(done); -#if JS_TRACE_LOGGING - logger->log(TraceLogging::GC_SWEEPING_STOP); -#endif break; - case ALLOCATING: -#if JS_TRACE_LOGGING - logger->log(TraceLogging::GC_ALLOCATING_START); -#endif + } + case ALLOCATING: { + AutoTraceLog logAllocating(logger, TraceLogger::GCAllocating); do { Chunk *chunk; { @@ -2598,21 +2588,15 @@ GCHelperThread::threadLoop() } /* OOM stops the background allocation. */ - if (!chunk) { -#if JS_TRACE_LOGGING - logger->log(TraceLogging::GC_ALLOCATING_STOP); -#endif + if (!chunk) break; - } JS_ASSERT(chunk->info.numArenasFreeCommitted == 0); rt->gcChunkPool.put(chunk); } while (state == ALLOCATING && rt->gcChunkPool.wantBackgroundAllocation(rt)); if (state == ALLOCATING) state = IDLE; -#if JS_TRACE_LOGGING - logger->log(TraceLogging::GC_ALLOCATING_STOP); -#endif break; + } case CANCEL_ALLOCATION: state = IDLE; PR_NotifyAllCondVar(done); @@ -4908,11 +4892,8 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget, if (rt->mainThread.suppressGC) return; -#if JS_TRACE_LOGGING - AutoTraceLog logger(TraceLogging::defaultLogger(), - TraceLogging::GC_START, - TraceLogging::GC_STOP); -#endif + TraceLogger *logger = TraceLoggerForMainThread(rt); + AutoTraceLog logGC(logger, TraceLogger::GC); #ifdef JS_GC_ZEAL if (rt->gcDeterministicOnly && !IsDeterministicGCReason(reason)) @@ -5071,11 +5052,8 @@ void js::MinorGC(JSRuntime *rt, JS::gcreason::Reason reason) { #ifdef JSGC_GENERATIONAL -#if JS_TRACE_LOGGING - AutoTraceLog logger(TraceLogging::defaultLogger(), - TraceLogging::MINOR_GC_START, - TraceLogging::MINOR_GC_STOP); -#endif + TraceLogger *logger = TraceLoggerForMainThread(rt); + AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC); rt->gcNursery.collect(rt, reason, nullptr); JS_ASSERT_IF(!rt->mainThread.suppressGC, rt->gcNursery.isEmpty()); #endif @@ -5087,11 +5065,9 @@ js::MinorGC(JSContext *cx, JS::gcreason::Reason reason) // Alternate to the runtime-taking form above which allows marking type // objects as needing pretenuring. #ifdef JSGC_GENERATIONAL -#if JS_TRACE_LOGGING - AutoTraceLog logger(TraceLogging::defaultLogger(), - TraceLogging::MINOR_GC_START, - TraceLogging::MINOR_GC_STOP); -#endif + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); + AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC); + Nursery::TypeObjectList pretenureTypes; JSRuntime *rt = cx->runtime(); rt->gcNursery.collect(cx->runtime(), reason, &pretenureTypes); diff --git a/js/src/jsworkers.cpp b/js/src/jsworkers.cpp index 37e004857e1..82ed9bf1a4a 100644 --- a/js/src/jsworkers.cpp +++ b/js/src/jsworkers.cpp @@ -12,6 +12,7 @@ #include "jsnativestack.h" #include "prmjtime.h" +#include "TraceLogging.h" #include "frontend/BytecodeCompiler.h" #include "jit/IonBuilder.h" @@ -779,12 +780,9 @@ WorkerThread::handleIonWorkload() ionBuilder = WorkerThreadState().ionWorklist().popCopy(); -#if JS_TRACE_LOGGING - AutoTraceLog logger(TraceLogging::getLogger(TraceLogging::ION_BACKGROUND_COMPILER), - TraceLogging::ION_COMPILE_START, - TraceLogging::ION_COMPILE_STOP, - ionBuilder->script()); -#endif + TraceLogger *logger = TraceLoggerForThread(thread); + AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, ionBuilder->script())); + AutoTraceLog logCompile(logger, TraceLogger::IonCompile); JSRuntime *rt = ionBuilder->script()->compartment()->runtimeFromAnyThread(); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 256ebd936e4..0f764e9ec1a 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -54,9 +54,6 @@ #include "jsworkers.h" #include "jswrapper.h" #include "prmjtime.h" -#if JS_TRACE_LOGGING -#include "TraceLogging.h" -#endif #include "builtin/TestingFunctions.h" #include "frontend/Parser.h" @@ -1542,9 +1539,6 @@ PrintInternal(JSContext *cx, const CallArgs &args, FILE *file) if (!bytes) return false; fprintf(file, "%s%s", i ? " " : "", bytes); -#if JS_TRACE_LOGGING - TraceLog(TraceLogging::defaultLogger(), bytes); -#endif JS_free(cx, bytes); } diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index e5bcdd3d56b..e06b369e2f0 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -29,9 +29,7 @@ #include "jsprf.h" #include "jsscript.h" #include "jsstr.h" -#if JS_TRACE_LOGGING #include "TraceLogging.h" -#endif #include "builtin/Eval.h" #include "jit/BaselineJIT.h" @@ -1466,10 +1464,10 @@ Interpret(JSContext *cx, RunState &state) RootedScript script(cx); SET_SCRIPT(REGS.fp()->script()); -#if JS_TRACE_LOGGING - TraceLogging::defaultLogger()->log(TraceLogging::SCRIPT_START, script); - TraceLogging::defaultLogger()->log(TraceLogging::INFO_ENGINE_INTERPRETER); -#endif + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); + uint32_t scriptLogId = TraceLogCreateTextId(logger, script); + TraceLogStartEvent(logger, scriptLogId); + TraceLogStartEvent(logger, TraceLogger::Interpreter); /* * Pool of rooters for use in this interpreter frame. References to these @@ -1801,9 +1799,11 @@ CASE(JSOP_RETRVAL) if (activation.entryFrame() != REGS.fp()) inline_return: { -#if JS_TRACE_LOGGING - TraceLogging::defaultLogger()->log(TraceLogging::SCRIPT_STOP); -#endif + // Stop the engine. (No details about which engine exactly, could be + // interpreter, Baseline or IonMonkey.) + TraceLogStopEvent(logger); + // Stop the script. (Again no details about which script exactly.) + TraceLogStopEvent(logger); if (MOZ_UNLIKELY(cx->compartment()->debugMode())) interpReturnOK = ScriptDebugEpilogue(cx, REGS.fp(), REGS.pc, interpReturnOK); @@ -2677,10 +2677,9 @@ CASE(JSOP_FUNCALL) SET_SCRIPT(REGS.fp()->script()); -#if JS_TRACE_LOGGING - TraceLogging::defaultLogger()->log(TraceLogging::SCRIPT_START, script); - TraceLogging::defaultLogger()->log(TraceLogging::INFO_ENGINE_INTERPRETER); -#endif + uint32_t scriptLogId = TraceLogCreateTextId(logger, script); + TraceLogStartEvent(logger, scriptLogId); + TraceLogStartEvent(logger, TraceLogger::Interpreter); if (!REGS.fp()->prologue(cx)) goto error; @@ -3511,9 +3510,8 @@ DEFAULT() gc::MaybeVerifyBarriers(cx, true); -#if JS_TRACE_LOGGING - TraceLogging::defaultLogger()->log(TraceLogging::SCRIPT_STOP); -#endif + TraceLogStopEvent(logger); + TraceLogStopEvent(logger, scriptLogId); #ifdef JS_ION /* diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index d7cf8c53773..774fd11367a 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -8,6 +8,8 @@ #include "mozilla/MemoryReporting.h" +#include "TraceLogging.h" + #include "frontend/TokenStream.h" #include "vm/MatchPairs.h" #include "vm/RegExpStatics.h" @@ -520,9 +522,14 @@ RegExpRunStatus RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex, MatchPairs &matches) { - /* Compile the code at point-of-use. */ - if (!compileIfNecessary(cx)) - return RegExpRunStatus_Error; + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); + + { + /* Compile the code at point-of-use. */ + AutoTraceLog logCompile(logger, TraceLogger::YarrCompile); + if (!compileIfNecessary(cx)) + return RegExpRunStatus_Error; + } /* Ensure sufficient memory for output vector. */ if (!matches.initArray(pairCount())) @@ -547,12 +554,18 @@ RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length, unsigned result; #if ENABLE_YARR_JIT - if (codeBlock.isFallBack()) + if (codeBlock.isFallBack()) { + AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret); result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, outputBuf); - else + } else { + AutoTraceLog logJIT(logger, TraceLogger::YarrJIT); result = codeBlock.execute(chars, start, length, (int *)outputBuf).start; + } #else - result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, outputBuf); + { + AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret); + result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, outputBuf); + } #endif if (result == JSC::Yarr::offsetError) { @@ -573,9 +586,14 @@ RegExpRunStatus RegExpShared::executeMatchOnly(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex, MatchPair &match) { - /* Compile the code at point-of-use. */ - if (!compileMatchOnlyIfNecessary(cx)) - return RegExpRunStatus_Error; + TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime()); + + { + /* Compile the code at point-of-use. */ + AutoTraceLog logCompile(logger, TraceLogger::YarrCompile); + if (!compileMatchOnlyIfNecessary(cx)) + return RegExpRunStatus_Error; + } #ifdef DEBUG const size_t origLength = length; @@ -592,6 +610,7 @@ RegExpShared::executeMatchOnly(JSContext *cx, const jschar *chars, size_t length #if ENABLE_YARR_JIT if (!codeBlock.isFallBack()) { + AutoTraceLog logJIT(logger, TraceLogger::YarrJIT); MatchResult result = codeBlock.execute(chars, start, length); if (!result) return RegExpRunStatus_Success_NotFound; @@ -613,8 +632,11 @@ RegExpShared::executeMatchOnly(JSContext *cx, const jschar *chars, size_t length if (!matches.initArray(pairCount())) return RegExpRunStatus_Error; - unsigned result = - JSC::Yarr::interpret(cx, bytecode, chars, length, start, matches.rawBuf()); + unsigned result; + { + AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret); + result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, matches.rawBuf()); + } if (result == JSC::Yarr::offsetError) { reportYarrError(cx, nullptr, JSC::Yarr::RuntimeError); diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 56cca873688..99864f36d33 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -72,6 +72,9 @@ PerThreadData::PerThreadData(JSRuntime *runtime) ionTop(nullptr), jitJSContext(nullptr), jitStackLimit(0), +#if JS_TRACE_LOGGING + traceLogger(nullptr), +#endif activation_(nullptr), asmJSActivationStack_(nullptr), #ifdef JS_ARM_SIMULATOR diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 652fb8cb1c8..f09f00d5eb1 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -56,6 +56,9 @@ namespace js { class PerThreadData; class ThreadSafeContext; class AutoKeepAtoms; +#if JS_TRACE_LOGGING +class TraceLogger; +#endif /* Thread Local Storage slot for storing the runtime for a thread. */ extern mozilla::ThreadLocal TlsPerThreadData; @@ -538,6 +541,10 @@ class PerThreadData : public PerThreadDataFriendFields inline void setJitStackLimit(uintptr_t limit); +#if JS_TRACE_LOGGING + TraceLogger *traceLogger; +#endif + /* * asm.js maintains a stack of AsmJSModule activations (see AsmJS.h). This * stack is used by JSRuntime::requestInterrupt to stop long-running asm.js diff --git a/js/src/yarr/YarrJIT.h b/js/src/yarr/YarrJIT.h index e919e304695..954d2a4d4d9 100644 --- a/js/src/yarr/YarrJIT.h +++ b/js/src/yarr/YarrJIT.h @@ -43,10 +43,6 @@ #define YARR_CALL #endif -#if JS_TRACE_LOGGING -#include "TraceLogging.h" -#endif - #include "jit/JitCommon.h" namespace JSC { @@ -99,12 +95,6 @@ public: { ASSERT(has8BitCode()); -#if JS_TRACE_LOGGING - js::AutoTraceLog logger(js::TraceLogging::defaultLogger(), - js::TraceLogging::YARR_JIT_START, - js::TraceLogging::YARR_JIT_STOP); -#endif - return MatchResult(reinterpret_cast(m_ref8.code().executableAddress())(input, start, length, output)); } @@ -112,12 +102,6 @@ public: { ASSERT(has8BitCodeMatchOnly()); -#if JS_TRACE_LOGGING - js::AutoTraceLog logger(js::TraceLogging::defaultLogger(), - js::TraceLogging::YARR_JIT_START, - js::TraceLogging::YARR_JIT_STOP); -#endif - return MatchResult(reinterpret_cast(m_matchOnly8.code().executableAddress())(input, start, length)); } #endif @@ -126,12 +110,6 @@ public: { ASSERT(has16BitCode()); -#if JS_TRACE_LOGGING - js::AutoTraceLog logger(js::TraceLogging::defaultLogger(), - js::TraceLogging::YARR_JIT_START, - js::TraceLogging::YARR_JIT_STOP); -#endif - YarrJITCode16 fn = JS_FUNC_TO_DATA_PTR(YarrJITCode16, m_ref16.code().executableAddress()); return MatchResult(CALL_GENERATED_YARR_CODE4(fn, input, start, length, output)); } @@ -140,12 +118,6 @@ public: { ASSERT(has16BitCodeMatchOnly()); -#if JS_TRACE_LOGGING - js::AutoTraceLog logger(js::TraceLogging::defaultLogger(), - js::TraceLogging::YARR_JIT_START, - js::TraceLogging::YARR_JIT_STOP); -#endif - YarrJITCodeMatchOnly16 fn = JS_FUNC_TO_DATA_PTR(YarrJITCodeMatchOnly16, m_matchOnly16.code().executableAddress()); return MatchResult(CALL_GENERATED_YARR_CODE3(fn, input, start, length)); }