Sat, 03 Jan 2015 20:18:00 +0100
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 }