js/src/vm/TraceLogging.h

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.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef TraceLogging_h
michael@0 8 #define TraceLogging_h
michael@0 9
michael@0 10 #include "jsalloc.h"
michael@0 11 #ifdef JS_THREADSAFE
michael@0 12 # include "jslock.h"
michael@0 13 #endif
michael@0 14
michael@0 15 #include "mozilla/GuardObjects.h"
michael@0 16
michael@0 17 #include "js/HashTable.h"
michael@0 18 #include "js/TypeDecls.h"
michael@0 19 #include "js/Vector.h"
michael@0 20
michael@0 21 struct JSRuntime;
michael@0 22
michael@0 23 namespace JS {
michael@0 24 class ReadOnlyCompileOptions;
michael@0 25 }
michael@0 26
michael@0 27 namespace js {
michael@0 28 class PerThreadData;
michael@0 29
michael@0 30 namespace jit {
michael@0 31 class CompileRuntime;
michael@0 32 }
michael@0 33
michael@0 34 /*
michael@0 35 * Tracelogging overview.
michael@0 36 *
michael@0 37 * Tracelogging makes it possible to trace the timestamp of a single event and/or
michael@0 38 * the duration of an event. This is implemented to give an as low overhead as
michael@0 39 * possible so it doesn't interfere with running.
michael@0 40 *
michael@0 41 * The output of a tracelogging session is saved in /tmp/tl-data.json.
michael@0 42 * The format of that file is a JS array per tracelogger (=thread), with a map
michael@0 43 * containing:
michael@0 44 * - dict: Name of the file containing a json table with the log text.
michael@0 45 * All other files only contain a index to this table when logging.
michael@0 46 * - events: Name of the file containing a flat list of log events saved
michael@0 47 * in binary format.
michael@0 48 * (64bit: Time Stamp Counter, 32bit index to dict)
michael@0 49 * - tree: Name of the file containing the events with duration. The content
michael@0 50 * is already in a tree data structure. This is also saved in a
michael@0 51 * binary file.
michael@0 52 * - treeFormat: The format used to encode the tree. By default "64,64,31,1,32".
michael@0 53 * There are currently no other formats to save the tree.
michael@0 54 * - 64,64,31,1,31 signifies how many bytes are used for the different
michael@0 55 * parts of the tree.
michael@0 56 * => 64 bits: Time Stamp Counter of start of event.
michael@0 57 * => 64 bits: Time Stamp Counter of end of event.
michael@0 58 * => 31 bits: Index to dict file containing the log text.
michael@0 59 * => 1 bit: Boolean signifying if this entry has children.
michael@0 60 * When true, the child can be found just behind this entry.
michael@0 61 * => 32 bits: Containing the ID of the next event on the same depth
michael@0 62 * or 0 if there isn't an event on the same depth anymore.
michael@0 63 *
michael@0 64 * /-> The position in the file. Id is this divided by size of entry.
michael@0 65 * | So in this case this would be 1 (192bits per entry).
michael@0 66 * | /-> Indicates there are children. The
michael@0 67 * | | first child is located at current
michael@0 68 * | | ID + 1. So 1 + 1 in this case: 2.
michael@0 69 * | | Or 0x00180 in the tree file.
michael@0 70 * | | /-> Next event on the same depth is
michael@0 71 * | | | located at 4. So 0x00300 in the
michael@0 72 * | | | tree file.
michael@0 73 * 0x0000C0: [start, end, dictId, 1, 4]
michael@0 74 *
michael@0 75 *
michael@0 76 * Example:
michael@0 77 * 0x0: [start, end, dictId, 1, 0]
michael@0 78 * |
michael@0 79 * /----------------------------------\
michael@0 80 * | |
michael@0 81 * 0xC0: [start, end, dictId, 0, 2] 0x180 [start, end, dictId, 1, 0]
michael@0 82 * |
michael@0 83 * /----------------------------------\
michael@0 84 * | |
michael@0 85 * 0x240: [start, end, dictId, 0, 4] 0x300 [start, end, dictId, 0, 0]
michael@0 86 *
michael@0 87 *
michael@0 88 * Logging something is done in 3 stages.
michael@0 89 * 1) Get the tracelogger of the current thread.
michael@0 90 * - TraceLoggerForMainThread(JSRuntime *)
michael@0 91 * - TraceLoggerForCurrentThread(); // Should NOT be used for the mainthread.
michael@0 92 * 2) Optionally create a textId for the text that needs to get logged. This
michael@0 93 * step takes some time, so try to do this beforehand, outside the hot
michael@0 94 * path and don't do unnecessary repetitions, since it will criple
michael@0 95 * performance.
michael@0 96 * - TraceLogCreateTextId(logger, ...);
michael@0 97 *
michael@0 98 * There are also some text IDs created beforehand. They are located in
michael@0 99 * Tracelogger::TextId.
michael@0 100 * 3) Log the timestamp of an event:
michael@0 101 * - TraceLogTimestamp(logger, textId);
michael@0 102 *
michael@0 103 * or the duration:
michael@0 104 * - TraceLogStartEvent(logger, textId);
michael@0 105 * - TraceLogStopEvent(logger, textId);
michael@0 106 *
michael@0 107 * or the duration with a RAII class:
michael@0 108 * - AutoTraceLog logger(logger, textId);
michael@0 109 */
michael@0 110
michael@0 111 #define TRACELOGGER_TEXT_ID_LIST(_) \
michael@0 112 _(Bailout) \
michael@0 113 _(Baseline) \
michael@0 114 _(BaselineCompilation) \
michael@0 115 _(GC) \
michael@0 116 _(GCAllocation) \
michael@0 117 _(GCSweeping) \
michael@0 118 _(Interpreter) \
michael@0 119 _(Invalidation) \
michael@0 120 _(IonCompilation) \
michael@0 121 _(IonLinking) \
michael@0 122 _(IonMonkey) \
michael@0 123 _(MinorGC) \
michael@0 124 _(ParserCompileFunction) \
michael@0 125 _(ParserCompileLazy) \
michael@0 126 _(ParserCompileScript) \
michael@0 127 _(TL) \
michael@0 128 _(YarrCompile) \
michael@0 129 _(YarrInterpret) \
michael@0 130 _(YarrJIT) \
michael@0 131 _(VM) \
michael@0 132 \
michael@0 133 /* Specific passes during ion compilation */ \
michael@0 134 _(SplitCriticalEdges) \
michael@0 135 _(RenumberBlocks) \
michael@0 136 _(DominatorTree) \
michael@0 137 _(PhiAnalysis) \
michael@0 138 _(ApplyTypes) \
michael@0 139 _(ParallelSafetyAnalysis) \
michael@0 140 _(AliasAnalysis) \
michael@0 141 _(GVN) \
michael@0 142 _(UCE) \
michael@0 143 _(LICM) \
michael@0 144 _(RangeAnalysis) \
michael@0 145 _(EffectiveAddressAnalysis) \
michael@0 146 _(EliminateDeadCode) \
michael@0 147 _(EdgeCaseAnalysis) \
michael@0 148 _(EliminateRedundantChecks)
michael@0 149
michael@0 150 class AutoTraceLog;
michael@0 151
michael@0 152 template <class T>
michael@0 153 class ContinuousSpace {
michael@0 154 T *data_;
michael@0 155 uint32_t next_;
michael@0 156 uint32_t capacity_;
michael@0 157
michael@0 158 public:
michael@0 159 ContinuousSpace ()
michael@0 160 : data_(nullptr)
michael@0 161 { }
michael@0 162
michael@0 163 bool init() {
michael@0 164 capacity_ = 64;
michael@0 165 next_ = 0;
michael@0 166 data_ = (T *) js_malloc(capacity_ * sizeof(T));
michael@0 167 if (!data_)
michael@0 168 return false;
michael@0 169
michael@0 170 return true;
michael@0 171 }
michael@0 172
michael@0 173 T *data() {
michael@0 174 return data_;
michael@0 175 }
michael@0 176
michael@0 177 uint32_t capacity() {
michael@0 178 return capacity_;
michael@0 179 }
michael@0 180
michael@0 181 uint32_t size() {
michael@0 182 return next_;
michael@0 183 }
michael@0 184
michael@0 185 uint32_t nextId() {
michael@0 186 return next_;
michael@0 187 }
michael@0 188
michael@0 189 T &next() {
michael@0 190 return data()[next_];
michael@0 191 }
michael@0 192
michael@0 193 uint32_t currentId() {
michael@0 194 MOZ_ASSERT(next_ > 0);
michael@0 195 return next_ - 1;
michael@0 196 }
michael@0 197
michael@0 198 T &current() {
michael@0 199 return data()[currentId()];
michael@0 200 }
michael@0 201
michael@0 202 bool ensureSpaceBeforeAdd(uint32_t count = 1) {
michael@0 203 if (next_ + count <= capacity_)
michael@0 204 return true;
michael@0 205
michael@0 206 uint32_t nCapacity = capacity_ * 2;
michael@0 207 if (next_ + count > nCapacity)
michael@0 208 nCapacity = next_ + count;
michael@0 209 T *entries = (T *) js_realloc(data_, nCapacity * sizeof(T));
michael@0 210
michael@0 211 if (!entries)
michael@0 212 return false;
michael@0 213
michael@0 214 data_ = entries;
michael@0 215 capacity_ = nCapacity;
michael@0 216
michael@0 217 return true;
michael@0 218 }
michael@0 219
michael@0 220 T &operator[](size_t i) {
michael@0 221 MOZ_ASSERT(i < next_);
michael@0 222 return data()[i];
michael@0 223 }
michael@0 224
michael@0 225 void push(T &data) {
michael@0 226 MOZ_ASSERT(next_ < capacity_);
michael@0 227 data()[next_++] = data;
michael@0 228 }
michael@0 229
michael@0 230 T &pushUninitialized() {
michael@0 231 MOZ_ASSERT(next_ < capacity_);
michael@0 232 return data()[next_++];
michael@0 233 }
michael@0 234
michael@0 235 void pop() {
michael@0 236 MOZ_ASSERT(next_ > 0);
michael@0 237 next_--;
michael@0 238 }
michael@0 239
michael@0 240 void clear() {
michael@0 241 next_ = 0;
michael@0 242 }
michael@0 243 };
michael@0 244
michael@0 245 class TraceLogger
michael@0 246 {
michael@0 247 public:
michael@0 248 // Predefined IDs for common operations. These IDs can be used
michael@0 249 // without using TraceLogCreateTextId, because there are already created.
michael@0 250 enum TextId {
michael@0 251 TL_Error = 0,
michael@0 252 # define DEFINE_TEXT_ID(textId) textId,
michael@0 253 TRACELOGGER_TEXT_ID_LIST(DEFINE_TEXT_ID)
michael@0 254 # undef DEFINE_TEXT_ID
michael@0 255 LAST
michael@0 256 };
michael@0 257
michael@0 258 #ifdef JS_TRACE_LOGGING
michael@0 259 private:
michael@0 260 typedef HashMap<const void *,
michael@0 261 uint32_t,
michael@0 262 PointerHasher<const void *, 3>,
michael@0 263 SystemAllocPolicy> PointerHashMap;
michael@0 264
michael@0 265 // The layout of the tree in memory and in the log file. Readable by JS
michael@0 266 // using TypedArrays.
michael@0 267 struct TreeEntry {
michael@0 268 uint64_t start_;
michael@0 269 uint64_t stop_;
michael@0 270 union {
michael@0 271 struct {
michael@0 272 uint32_t textId_: 31;
michael@0 273 uint32_t hasChildren_: 1;
michael@0 274 } s;
michael@0 275 uint32_t value_;
michael@0 276 } u;
michael@0 277 uint32_t nextId_;
michael@0 278
michael@0 279 TreeEntry(uint64_t start, uint64_t stop, uint32_t textId, bool hasChildren,
michael@0 280 uint32_t nextId)
michael@0 281 {
michael@0 282 start_ = start;
michael@0 283 stop_ = stop;
michael@0 284 u.s.textId_ = textId;
michael@0 285 u.s.hasChildren_ = hasChildren;
michael@0 286 nextId_ = nextId;
michael@0 287 }
michael@0 288 TreeEntry()
michael@0 289 { }
michael@0 290 uint64_t start() {
michael@0 291 return start_;
michael@0 292 }
michael@0 293 uint64_t stop() {
michael@0 294 return stop_;
michael@0 295 }
michael@0 296 uint32_t textId() {
michael@0 297 return u.s.textId_;
michael@0 298 }
michael@0 299 bool hasChildren() {
michael@0 300 return u.s.hasChildren_;
michael@0 301 }
michael@0 302 uint32_t nextId() {
michael@0 303 return nextId_;
michael@0 304 }
michael@0 305 void setStart(uint64_t start) {
michael@0 306 start_ = start;
michael@0 307 }
michael@0 308 void setStop(uint64_t stop) {
michael@0 309 stop_ = stop;
michael@0 310 }
michael@0 311 void setTextId(uint32_t textId) {
michael@0 312 MOZ_ASSERT(textId < uint32_t(1<<31) );
michael@0 313 u.s.textId_ = textId;
michael@0 314 }
michael@0 315 void setHasChildren(bool hasChildren) {
michael@0 316 u.s.hasChildren_ = hasChildren;
michael@0 317 }
michael@0 318 void setNextId(uint32_t nextId) {
michael@0 319 nextId_ = nextId;
michael@0 320 }
michael@0 321 };
michael@0 322
michael@0 323 // Helper structure for keeping track of the current entries in
michael@0 324 // the tree. Pushed by `start(id)`, popped by `stop(id)`. The active flag
michael@0 325 // is used to know if a subtree doesn't need to get logged.
michael@0 326 struct StackEntry {
michael@0 327 uint32_t treeId_;
michael@0 328 uint32_t lastChildId_;
michael@0 329 struct {
michael@0 330 uint32_t textId_: 31;
michael@0 331 uint32_t active_: 1;
michael@0 332 } s;
michael@0 333 StackEntry(uint32_t treeId, uint32_t lastChildId, bool active = true)
michael@0 334 : treeId_(treeId), lastChildId_(lastChildId)
michael@0 335 {
michael@0 336 s.textId_ = 0;
michael@0 337 s.active_ = active;
michael@0 338 }
michael@0 339 uint32_t treeId() {
michael@0 340 return treeId_;
michael@0 341 }
michael@0 342 uint32_t lastChildId() {
michael@0 343 return lastChildId_;
michael@0 344 }
michael@0 345 uint32_t textId() {
michael@0 346 return s.textId_;
michael@0 347 }
michael@0 348 bool active() {
michael@0 349 return s.active_;
michael@0 350 }
michael@0 351 void setTreeId(uint32_t treeId) {
michael@0 352 treeId_ = treeId;
michael@0 353 }
michael@0 354 void setLastChildId(uint32_t lastChildId) {
michael@0 355 lastChildId_ = lastChildId;
michael@0 356 }
michael@0 357 void setTextId(uint32_t textId) {
michael@0 358 MOZ_ASSERT(textId < uint32_t(1<<31) );
michael@0 359 s.textId_ = textId;
michael@0 360 }
michael@0 361 void setActive(bool active) {
michael@0 362 s.active_ = active;
michael@0 363 }
michael@0 364 };
michael@0 365
michael@0 366 // The layout of the event log in memory and in the log file.
michael@0 367 // Readable by JS using TypedArrays.
michael@0 368 struct EventEntry {
michael@0 369 uint64_t time;
michael@0 370 uint32_t textId;
michael@0 371 EventEntry(uint64_t time, uint32_t textId)
michael@0 372 : time(time), textId(textId)
michael@0 373 { }
michael@0 374 };
michael@0 375
michael@0 376 FILE *dictFile;
michael@0 377 FILE *treeFile;
michael@0 378 FILE *eventFile;
michael@0 379
michael@0 380 bool enabled;
michael@0 381 uint32_t enabledTimes;
michael@0 382 bool failed;
michael@0 383 uint32_t nextTextId;
michael@0 384
michael@0 385 PointerHashMap pointerMap;
michael@0 386
michael@0 387 ContinuousSpace<TreeEntry> tree;
michael@0 388 ContinuousSpace<StackEntry> stack;
michael@0 389 ContinuousSpace<EventEntry> events;
michael@0 390
michael@0 391 uint32_t treeOffset;
michael@0 392
michael@0 393 public:
michael@0 394 AutoTraceLog *top;
michael@0 395
michael@0 396 private:
michael@0 397 // Helper functions that convert a TreeEntry in different endianness
michael@0 398 // in place.
michael@0 399 void entryToBigEndian(TreeEntry *entry);
michael@0 400 void entryToSystemEndian(TreeEntry *entry);
michael@0 401
michael@0 402 // Helper functions to get/save a tree from file.
michael@0 403 bool getTreeEntry(uint32_t treeId, TreeEntry *entry);
michael@0 404 bool saveTreeEntry(uint32_t treeId, TreeEntry *entry);
michael@0 405
michael@0 406 // Return the first StackEntry that is active.
michael@0 407 StackEntry &getActiveAncestor();
michael@0 408
michael@0 409 // This contains the meat of startEvent, except the test for enough space,
michael@0 410 // the test if tracelogger is enabled and the timestamp computation.
michael@0 411 bool startEvent(uint32_t id, uint64_t timestamp);
michael@0 412
michael@0 413 // Update functions that can adjust the items in the tree,
michael@0 414 // both in memory or already written to disk.
michael@0 415 bool updateHasChildren(uint32_t treeId, bool hasChildren = true);
michael@0 416 bool updateNextId(uint32_t treeId, uint32_t nextId);
michael@0 417 bool updateStop(uint32_t treeId, uint64_t timestamp);
michael@0 418
michael@0 419 // Flush the tree and events.
michael@0 420 bool flush();
michael@0 421
michael@0 422 public:
michael@0 423 TraceLogger();
michael@0 424 ~TraceLogger();
michael@0 425
michael@0 426 bool init(uint32_t loggerId);
michael@0 427
michael@0 428 bool enable();
michael@0 429 bool disable();
michael@0 430
michael@0 431 // The createTextId functions map a unique input to a logger ID.
michael@0 432 // This ID can be used to log something. Calls to these functions should be
michael@0 433 // limited if possible, because of the overhead.
michael@0 434 uint32_t createTextId(const char *text);
michael@0 435 uint32_t createTextId(JSScript *script);
michael@0 436 uint32_t createTextId(const JS::ReadOnlyCompileOptions &script);
michael@0 437
michael@0 438 // Log an event (no start/stop, only the timestamp is recorded).
michael@0 439 void logTimestamp(uint32_t id);
michael@0 440
michael@0 441 // Record timestamps for start and stop of an event.
michael@0 442 // In the stop method, the ID is only used in debug builds to test
michael@0 443 // correctness.
michael@0 444 void startEvent(uint32_t id);
michael@0 445 void stopEvent(uint32_t id);
michael@0 446 void stopEvent();
michael@0 447
michael@0 448 private:
michael@0 449 void assertNoQuotes(const char *text) {
michael@0 450 #ifdef DEBUG
michael@0 451 const char *quote = strchr(text, '"');
michael@0 452 MOZ_ASSERT(!quote);
michael@0 453 #endif
michael@0 454 }
michael@0 455 #endif
michael@0 456 };
michael@0 457
michael@0 458 class TraceLogging
michael@0 459 {
michael@0 460 #ifdef JS_TRACE_LOGGING
michael@0 461 #ifdef JS_THREADSAFE
michael@0 462 typedef HashMap<PRThread *,
michael@0 463 TraceLogger *,
michael@0 464 PointerHasher<PRThread *, 3>,
michael@0 465 SystemAllocPolicy> ThreadLoggerHashMap;
michael@0 466 #endif // JS_THREADSAFE
michael@0 467 typedef Vector<TraceLogger *, 1, js::SystemAllocPolicy > MainThreadLoggers;
michael@0 468
michael@0 469 bool initialized;
michael@0 470 bool enabled;
michael@0 471 bool enabledTextIds[TraceLogger::LAST];
michael@0 472 bool mainThreadEnabled;
michael@0 473 bool offThreadEnabled;
michael@0 474 #ifdef JS_THREADSAFE
michael@0 475 ThreadLoggerHashMap threadLoggers;
michael@0 476 #endif // JS_THREADSAFE
michael@0 477 MainThreadLoggers mainThreadLoggers;
michael@0 478 uint32_t loggerId;
michael@0 479 FILE *out;
michael@0 480
michael@0 481 public:
michael@0 482 uint64_t startupTime;
michael@0 483 #ifdef JS_THREADSAFE
michael@0 484 PRLock *lock;
michael@0 485 #endif // JS_THREADSAFE
michael@0 486
michael@0 487 TraceLogging();
michael@0 488 ~TraceLogging();
michael@0 489
michael@0 490 TraceLogger *forMainThread(JSRuntime *runtime);
michael@0 491 TraceLogger *forMainThread(jit::CompileRuntime *runtime);
michael@0 492 #ifdef JS_THREADSAFE
michael@0 493 TraceLogger *forThread(PRThread *thread);
michael@0 494 #endif // JS_THREADSAFE
michael@0 495
michael@0 496 bool isTextIdEnabled(uint32_t textId) {
michael@0 497 if (textId < TraceLogger::LAST)
michael@0 498 return enabledTextIds[textId];
michael@0 499 return true;
michael@0 500 }
michael@0 501
michael@0 502 private:
michael@0 503 TraceLogger *forMainThread(PerThreadData *mainThread);
michael@0 504 TraceLogger *create();
michael@0 505 bool lazyInit();
michael@0 506 #endif
michael@0 507 };
michael@0 508
michael@0 509 #ifdef JS_TRACE_LOGGING
michael@0 510 TraceLogger *TraceLoggerForMainThread(JSRuntime *runtime);
michael@0 511 TraceLogger *TraceLoggerForMainThread(jit::CompileRuntime *runtime);
michael@0 512 TraceLogger *TraceLoggerForCurrentThread();
michael@0 513 #else
michael@0 514 inline TraceLogger *TraceLoggerForMainThread(JSRuntime *runtime) {
michael@0 515 return nullptr;
michael@0 516 };
michael@0 517 inline TraceLogger *TraceLoggerForMainThread(jit::CompileRuntime *runtime) {
michael@0 518 return nullptr;
michael@0 519 };
michael@0 520 inline TraceLogger *TraceLoggerForCurrentThread() {
michael@0 521 return nullptr;
michael@0 522 };
michael@0 523 #endif
michael@0 524
michael@0 525 inline bool TraceLoggerEnable(TraceLogger *logger) {
michael@0 526 #ifdef JS_TRACE_LOGGING
michael@0 527 if (logger)
michael@0 528 return logger->enable();
michael@0 529 #endif
michael@0 530 return false;
michael@0 531 }
michael@0 532 inline bool TraceLoggerDisable(TraceLogger *logger) {
michael@0 533 #ifdef JS_TRACE_LOGGING
michael@0 534 if (logger)
michael@0 535 return logger->disable();
michael@0 536 #endif
michael@0 537 return false;
michael@0 538 }
michael@0 539
michael@0 540 inline uint32_t TraceLogCreateTextId(TraceLogger *logger, JSScript *script) {
michael@0 541 #ifdef JS_TRACE_LOGGING
michael@0 542 if (logger)
michael@0 543 return logger->createTextId(script);
michael@0 544 #endif
michael@0 545 return TraceLogger::TL_Error;
michael@0 546 }
michael@0 547 inline uint32_t TraceLogCreateTextId(TraceLogger *logger,
michael@0 548 const JS::ReadOnlyCompileOptions &compileOptions)
michael@0 549 {
michael@0 550 #ifdef JS_TRACE_LOGGING
michael@0 551 if (logger)
michael@0 552 return logger->createTextId(compileOptions);
michael@0 553 #endif
michael@0 554 return TraceLogger::TL_Error;
michael@0 555 }
michael@0 556 inline uint32_t TraceLogCreateTextId(TraceLogger *logger, const char *text) {
michael@0 557 #ifdef JS_TRACE_LOGGING
michael@0 558 if (logger)
michael@0 559 return logger->createTextId(text);
michael@0 560 #endif
michael@0 561 return TraceLogger::TL_Error;
michael@0 562 }
michael@0 563 #ifdef JS_TRACE_LOGGING
michael@0 564 bool TraceLogTextIdEnabled(uint32_t textId);
michael@0 565 #else
michael@0 566 inline bool TraceLogTextIdEnabled(uint32_t textId) {
michael@0 567 return false;
michael@0 568 }
michael@0 569 #endif
michael@0 570 inline void TraceLogTimestamp(TraceLogger *logger, uint32_t textId) {
michael@0 571 #ifdef JS_TRACE_LOGGING
michael@0 572 if (logger)
michael@0 573 logger->logTimestamp(textId);
michael@0 574 #endif
michael@0 575 }
michael@0 576 inline void TraceLogStartEvent(TraceLogger *logger, uint32_t textId) {
michael@0 577 #ifdef JS_TRACE_LOGGING
michael@0 578 if (logger)
michael@0 579 logger->startEvent(textId);
michael@0 580 #endif
michael@0 581 }
michael@0 582 inline void TraceLogStopEvent(TraceLogger *logger, uint32_t textId) {
michael@0 583 #ifdef JS_TRACE_LOGGING
michael@0 584 if (logger)
michael@0 585 logger->stopEvent(textId);
michael@0 586 #endif
michael@0 587 }
michael@0 588 inline void TraceLogStopEvent(TraceLogger *logger) {
michael@0 589 #ifdef JS_TRACE_LOGGING
michael@0 590 if (logger)
michael@0 591 logger->stopEvent();
michael@0 592 #endif
michael@0 593 }
michael@0 594
michael@0 595 // Automatic logging at the start and end of function call.
michael@0 596 class AutoTraceLog {
michael@0 597 #ifdef JS_TRACE_LOGGING
michael@0 598 TraceLogger *logger;
michael@0 599 uint32_t textId;
michael@0 600 bool executed;
michael@0 601 AutoTraceLog *prev;
michael@0 602
michael@0 603 public:
michael@0 604 AutoTraceLog(TraceLogger *logger, uint32_t textId MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 605 : logger(logger),
michael@0 606 textId(textId),
michael@0 607 executed(false)
michael@0 608 {
michael@0 609 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 610 if (logger) {
michael@0 611 TraceLogStartEvent(logger, textId);
michael@0 612
michael@0 613 prev = logger->top;
michael@0 614 logger->top = this;
michael@0 615 }
michael@0 616 }
michael@0 617
michael@0 618 ~AutoTraceLog()
michael@0 619 {
michael@0 620 if (logger) {
michael@0 621 while (this != logger->top)
michael@0 622 logger->top->stop();
michael@0 623 stop();
michael@0 624 }
michael@0 625 }
michael@0 626 private:
michael@0 627 void stop() {
michael@0 628 if (!executed) {
michael@0 629 executed = true;
michael@0 630 TraceLogStopEvent(logger, textId);
michael@0 631 }
michael@0 632
michael@0 633 if (logger->top == this)
michael@0 634 logger->top = prev;
michael@0 635 }
michael@0 636 #else
michael@0 637 public:
michael@0 638 AutoTraceLog(TraceLogger *logger, uint32_t textId MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 639 {
michael@0 640 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 641 }
michael@0 642 #endif
michael@0 643
michael@0 644 private:
michael@0 645 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
michael@0 646 };
michael@0 647
michael@0 648 #ifdef JS_TRACE_LOGGING
michael@0 649 class AutoTraceLoggingLock
michael@0 650 {
michael@0 651 TraceLogging *logging;
michael@0 652
michael@0 653 public:
michael@0 654 AutoTraceLoggingLock(TraceLogging *logging MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 655 : logging(logging)
michael@0 656 {
michael@0 657 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 658 #ifdef JS_THREADSAFE
michael@0 659 PR_Lock(logging->lock);
michael@0 660 #endif // JS_THREADSAFE
michael@0 661 }
michael@0 662 ~AutoTraceLoggingLock() {
michael@0 663 #ifdef JS_THREADSAFE
michael@0 664 PR_Unlock(logging->lock);
michael@0 665 #endif // JS_THREADSAFE
michael@0 666 }
michael@0 667 private:
michael@0 668 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
michael@0 669 };
michael@0 670 #endif
michael@0 671
michael@0 672 } /* namedata js */
michael@0 673
michael@0 674 #endif /* TraceLogging_h */

mercurial