1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/TraceLogging.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,674 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef TraceLogging_h 1.11 +#define TraceLogging_h 1.12 + 1.13 +#include "jsalloc.h" 1.14 +#ifdef JS_THREADSAFE 1.15 +# include "jslock.h" 1.16 +#endif 1.17 + 1.18 +#include "mozilla/GuardObjects.h" 1.19 + 1.20 +#include "js/HashTable.h" 1.21 +#include "js/TypeDecls.h" 1.22 +#include "js/Vector.h" 1.23 + 1.24 +struct JSRuntime; 1.25 + 1.26 +namespace JS { 1.27 + class ReadOnlyCompileOptions; 1.28 +} 1.29 + 1.30 +namespace js { 1.31 +class PerThreadData; 1.32 + 1.33 +namespace jit { 1.34 + class CompileRuntime; 1.35 +} 1.36 + 1.37 +/* 1.38 + * Tracelogging overview. 1.39 + * 1.40 + * Tracelogging makes it possible to trace the timestamp of a single event and/or 1.41 + * the duration of an event. This is implemented to give an as low overhead as 1.42 + * possible so it doesn't interfere with running. 1.43 + * 1.44 + * The output of a tracelogging session is saved in /tmp/tl-data.json. 1.45 + * The format of that file is a JS array per tracelogger (=thread), with a map 1.46 + * containing: 1.47 + * - dict: Name of the file containing a json table with the log text. 1.48 + * All other files only contain a index to this table when logging. 1.49 + * - events: Name of the file containing a flat list of log events saved 1.50 + * in binary format. 1.51 + * (64bit: Time Stamp Counter, 32bit index to dict) 1.52 + * - tree: Name of the file containing the events with duration. The content 1.53 + * is already in a tree data structure. This is also saved in a 1.54 + * binary file. 1.55 + * - treeFormat: The format used to encode the tree. By default "64,64,31,1,32". 1.56 + * There are currently no other formats to save the tree. 1.57 + * - 64,64,31,1,31 signifies how many bytes are used for the different 1.58 + * parts of the tree. 1.59 + * => 64 bits: Time Stamp Counter of start of event. 1.60 + * => 64 bits: Time Stamp Counter of end of event. 1.61 + * => 31 bits: Index to dict file containing the log text. 1.62 + * => 1 bit: Boolean signifying if this entry has children. 1.63 + * When true, the child can be found just behind this entry. 1.64 + * => 32 bits: Containing the ID of the next event on the same depth 1.65 + * or 0 if there isn't an event on the same depth anymore. 1.66 + * 1.67 + * /-> The position in the file. Id is this divided by size of entry. 1.68 + * | So in this case this would be 1 (192bits per entry). 1.69 + * | /-> Indicates there are children. The 1.70 + * | | first child is located at current 1.71 + * | | ID + 1. So 1 + 1 in this case: 2. 1.72 + * | | Or 0x00180 in the tree file. 1.73 + * | | /-> Next event on the same depth is 1.74 + * | | | located at 4. So 0x00300 in the 1.75 + * | | | tree file. 1.76 + * 0x0000C0: [start, end, dictId, 1, 4] 1.77 + * 1.78 + * 1.79 + * Example: 1.80 + * 0x0: [start, end, dictId, 1, 0] 1.81 + * | 1.82 + * /----------------------------------\ 1.83 + * | | 1.84 + * 0xC0: [start, end, dictId, 0, 2] 0x180 [start, end, dictId, 1, 0] 1.85 + * | 1.86 + * /----------------------------------\ 1.87 + * | | 1.88 + * 0x240: [start, end, dictId, 0, 4] 0x300 [start, end, dictId, 0, 0] 1.89 + * 1.90 + * 1.91 + * Logging something is done in 3 stages. 1.92 + * 1) Get the tracelogger of the current thread. 1.93 + * - TraceLoggerForMainThread(JSRuntime *) 1.94 + * - TraceLoggerForCurrentThread(); // Should NOT be used for the mainthread. 1.95 + * 2) Optionally create a textId for the text that needs to get logged. This 1.96 + * step takes some time, so try to do this beforehand, outside the hot 1.97 + * path and don't do unnecessary repetitions, since it will criple 1.98 + * performance. 1.99 + * - TraceLogCreateTextId(logger, ...); 1.100 + * 1.101 + * There are also some text IDs created beforehand. They are located in 1.102 + * Tracelogger::TextId. 1.103 + * 3) Log the timestamp of an event: 1.104 + * - TraceLogTimestamp(logger, textId); 1.105 + * 1.106 + * or the duration: 1.107 + * - TraceLogStartEvent(logger, textId); 1.108 + * - TraceLogStopEvent(logger, textId); 1.109 + * 1.110 + * or the duration with a RAII class: 1.111 + * - AutoTraceLog logger(logger, textId); 1.112 + */ 1.113 + 1.114 +#define TRACELOGGER_TEXT_ID_LIST(_) \ 1.115 + _(Bailout) \ 1.116 + _(Baseline) \ 1.117 + _(BaselineCompilation) \ 1.118 + _(GC) \ 1.119 + _(GCAllocation) \ 1.120 + _(GCSweeping) \ 1.121 + _(Interpreter) \ 1.122 + _(Invalidation) \ 1.123 + _(IonCompilation) \ 1.124 + _(IonLinking) \ 1.125 + _(IonMonkey) \ 1.126 + _(MinorGC) \ 1.127 + _(ParserCompileFunction) \ 1.128 + _(ParserCompileLazy) \ 1.129 + _(ParserCompileScript) \ 1.130 + _(TL) \ 1.131 + _(YarrCompile) \ 1.132 + _(YarrInterpret) \ 1.133 + _(YarrJIT) \ 1.134 + _(VM) \ 1.135 + \ 1.136 + /* Specific passes during ion compilation */ \ 1.137 + _(SplitCriticalEdges) \ 1.138 + _(RenumberBlocks) \ 1.139 + _(DominatorTree) \ 1.140 + _(PhiAnalysis) \ 1.141 + _(ApplyTypes) \ 1.142 + _(ParallelSafetyAnalysis) \ 1.143 + _(AliasAnalysis) \ 1.144 + _(GVN) \ 1.145 + _(UCE) \ 1.146 + _(LICM) \ 1.147 + _(RangeAnalysis) \ 1.148 + _(EffectiveAddressAnalysis) \ 1.149 + _(EliminateDeadCode) \ 1.150 + _(EdgeCaseAnalysis) \ 1.151 + _(EliminateRedundantChecks) 1.152 + 1.153 +class AutoTraceLog; 1.154 + 1.155 +template <class T> 1.156 +class ContinuousSpace { 1.157 + T *data_; 1.158 + uint32_t next_; 1.159 + uint32_t capacity_; 1.160 + 1.161 + public: 1.162 + ContinuousSpace () 1.163 + : data_(nullptr) 1.164 + { } 1.165 + 1.166 + bool init() { 1.167 + capacity_ = 64; 1.168 + next_ = 0; 1.169 + data_ = (T *) js_malloc(capacity_ * sizeof(T)); 1.170 + if (!data_) 1.171 + return false; 1.172 + 1.173 + return true; 1.174 + } 1.175 + 1.176 + T *data() { 1.177 + return data_; 1.178 + } 1.179 + 1.180 + uint32_t capacity() { 1.181 + return capacity_; 1.182 + } 1.183 + 1.184 + uint32_t size() { 1.185 + return next_; 1.186 + } 1.187 + 1.188 + uint32_t nextId() { 1.189 + return next_; 1.190 + } 1.191 + 1.192 + T &next() { 1.193 + return data()[next_]; 1.194 + } 1.195 + 1.196 + uint32_t currentId() { 1.197 + MOZ_ASSERT(next_ > 0); 1.198 + return next_ - 1; 1.199 + } 1.200 + 1.201 + T ¤t() { 1.202 + return data()[currentId()]; 1.203 + } 1.204 + 1.205 + bool ensureSpaceBeforeAdd(uint32_t count = 1) { 1.206 + if (next_ + count <= capacity_) 1.207 + return true; 1.208 + 1.209 + uint32_t nCapacity = capacity_ * 2; 1.210 + if (next_ + count > nCapacity) 1.211 + nCapacity = next_ + count; 1.212 + T *entries = (T *) js_realloc(data_, nCapacity * sizeof(T)); 1.213 + 1.214 + if (!entries) 1.215 + return false; 1.216 + 1.217 + data_ = entries; 1.218 + capacity_ = nCapacity; 1.219 + 1.220 + return true; 1.221 + } 1.222 + 1.223 + T &operator[](size_t i) { 1.224 + MOZ_ASSERT(i < next_); 1.225 + return data()[i]; 1.226 + } 1.227 + 1.228 + void push(T &data) { 1.229 + MOZ_ASSERT(next_ < capacity_); 1.230 + data()[next_++] = data; 1.231 + } 1.232 + 1.233 + T &pushUninitialized() { 1.234 + MOZ_ASSERT(next_ < capacity_); 1.235 + return data()[next_++]; 1.236 + } 1.237 + 1.238 + void pop() { 1.239 + MOZ_ASSERT(next_ > 0); 1.240 + next_--; 1.241 + } 1.242 + 1.243 + void clear() { 1.244 + next_ = 0; 1.245 + } 1.246 +}; 1.247 + 1.248 +class TraceLogger 1.249 +{ 1.250 + public: 1.251 + // Predefined IDs for common operations. These IDs can be used 1.252 + // without using TraceLogCreateTextId, because there are already created. 1.253 + enum TextId { 1.254 + TL_Error = 0, 1.255 +# define DEFINE_TEXT_ID(textId) textId, 1.256 + TRACELOGGER_TEXT_ID_LIST(DEFINE_TEXT_ID) 1.257 +# undef DEFINE_TEXT_ID 1.258 + LAST 1.259 + }; 1.260 + 1.261 +#ifdef JS_TRACE_LOGGING 1.262 + private: 1.263 + typedef HashMap<const void *, 1.264 + uint32_t, 1.265 + PointerHasher<const void *, 3>, 1.266 + SystemAllocPolicy> PointerHashMap; 1.267 + 1.268 + // The layout of the tree in memory and in the log file. Readable by JS 1.269 + // using TypedArrays. 1.270 + struct TreeEntry { 1.271 + uint64_t start_; 1.272 + uint64_t stop_; 1.273 + union { 1.274 + struct { 1.275 + uint32_t textId_: 31; 1.276 + uint32_t hasChildren_: 1; 1.277 + } s; 1.278 + uint32_t value_; 1.279 + } u; 1.280 + uint32_t nextId_; 1.281 + 1.282 + TreeEntry(uint64_t start, uint64_t stop, uint32_t textId, bool hasChildren, 1.283 + uint32_t nextId) 1.284 + { 1.285 + start_ = start; 1.286 + stop_ = stop; 1.287 + u.s.textId_ = textId; 1.288 + u.s.hasChildren_ = hasChildren; 1.289 + nextId_ = nextId; 1.290 + } 1.291 + TreeEntry() 1.292 + { } 1.293 + uint64_t start() { 1.294 + return start_; 1.295 + } 1.296 + uint64_t stop() { 1.297 + return stop_; 1.298 + } 1.299 + uint32_t textId() { 1.300 + return u.s.textId_; 1.301 + } 1.302 + bool hasChildren() { 1.303 + return u.s.hasChildren_; 1.304 + } 1.305 + uint32_t nextId() { 1.306 + return nextId_; 1.307 + } 1.308 + void setStart(uint64_t start) { 1.309 + start_ = start; 1.310 + } 1.311 + void setStop(uint64_t stop) { 1.312 + stop_ = stop; 1.313 + } 1.314 + void setTextId(uint32_t textId) { 1.315 + MOZ_ASSERT(textId < uint32_t(1<<31) ); 1.316 + u.s.textId_ = textId; 1.317 + } 1.318 + void setHasChildren(bool hasChildren) { 1.319 + u.s.hasChildren_ = hasChildren; 1.320 + } 1.321 + void setNextId(uint32_t nextId) { 1.322 + nextId_ = nextId; 1.323 + } 1.324 + }; 1.325 + 1.326 + // Helper structure for keeping track of the current entries in 1.327 + // the tree. Pushed by `start(id)`, popped by `stop(id)`. The active flag 1.328 + // is used to know if a subtree doesn't need to get logged. 1.329 + struct StackEntry { 1.330 + uint32_t treeId_; 1.331 + uint32_t lastChildId_; 1.332 + struct { 1.333 + uint32_t textId_: 31; 1.334 + uint32_t active_: 1; 1.335 + } s; 1.336 + StackEntry(uint32_t treeId, uint32_t lastChildId, bool active = true) 1.337 + : treeId_(treeId), lastChildId_(lastChildId) 1.338 + { 1.339 + s.textId_ = 0; 1.340 + s.active_ = active; 1.341 + } 1.342 + uint32_t treeId() { 1.343 + return treeId_; 1.344 + } 1.345 + uint32_t lastChildId() { 1.346 + return lastChildId_; 1.347 + } 1.348 + uint32_t textId() { 1.349 + return s.textId_; 1.350 + } 1.351 + bool active() { 1.352 + return s.active_; 1.353 + } 1.354 + void setTreeId(uint32_t treeId) { 1.355 + treeId_ = treeId; 1.356 + } 1.357 + void setLastChildId(uint32_t lastChildId) { 1.358 + lastChildId_ = lastChildId; 1.359 + } 1.360 + void setTextId(uint32_t textId) { 1.361 + MOZ_ASSERT(textId < uint32_t(1<<31) ); 1.362 + s.textId_ = textId; 1.363 + } 1.364 + void setActive(bool active) { 1.365 + s.active_ = active; 1.366 + } 1.367 + }; 1.368 + 1.369 + // The layout of the event log in memory and in the log file. 1.370 + // Readable by JS using TypedArrays. 1.371 + struct EventEntry { 1.372 + uint64_t time; 1.373 + uint32_t textId; 1.374 + EventEntry(uint64_t time, uint32_t textId) 1.375 + : time(time), textId(textId) 1.376 + { } 1.377 + }; 1.378 + 1.379 + FILE *dictFile; 1.380 + FILE *treeFile; 1.381 + FILE *eventFile; 1.382 + 1.383 + bool enabled; 1.384 + uint32_t enabledTimes; 1.385 + bool failed; 1.386 + uint32_t nextTextId; 1.387 + 1.388 + PointerHashMap pointerMap; 1.389 + 1.390 + ContinuousSpace<TreeEntry> tree; 1.391 + ContinuousSpace<StackEntry> stack; 1.392 + ContinuousSpace<EventEntry> events; 1.393 + 1.394 + uint32_t treeOffset; 1.395 + 1.396 + public: 1.397 + AutoTraceLog *top; 1.398 + 1.399 + private: 1.400 + // Helper functions that convert a TreeEntry in different endianness 1.401 + // in place. 1.402 + void entryToBigEndian(TreeEntry *entry); 1.403 + void entryToSystemEndian(TreeEntry *entry); 1.404 + 1.405 + // Helper functions to get/save a tree from file. 1.406 + bool getTreeEntry(uint32_t treeId, TreeEntry *entry); 1.407 + bool saveTreeEntry(uint32_t treeId, TreeEntry *entry); 1.408 + 1.409 + // Return the first StackEntry that is active. 1.410 + StackEntry &getActiveAncestor(); 1.411 + 1.412 + // This contains the meat of startEvent, except the test for enough space, 1.413 + // the test if tracelogger is enabled and the timestamp computation. 1.414 + bool startEvent(uint32_t id, uint64_t timestamp); 1.415 + 1.416 + // Update functions that can adjust the items in the tree, 1.417 + // both in memory or already written to disk. 1.418 + bool updateHasChildren(uint32_t treeId, bool hasChildren = true); 1.419 + bool updateNextId(uint32_t treeId, uint32_t nextId); 1.420 + bool updateStop(uint32_t treeId, uint64_t timestamp); 1.421 + 1.422 + // Flush the tree and events. 1.423 + bool flush(); 1.424 + 1.425 + public: 1.426 + TraceLogger(); 1.427 + ~TraceLogger(); 1.428 + 1.429 + bool init(uint32_t loggerId); 1.430 + 1.431 + bool enable(); 1.432 + bool disable(); 1.433 + 1.434 + // The createTextId functions map a unique input to a logger ID. 1.435 + // This ID can be used to log something. Calls to these functions should be 1.436 + // limited if possible, because of the overhead. 1.437 + uint32_t createTextId(const char *text); 1.438 + uint32_t createTextId(JSScript *script); 1.439 + uint32_t createTextId(const JS::ReadOnlyCompileOptions &script); 1.440 + 1.441 + // Log an event (no start/stop, only the timestamp is recorded). 1.442 + void logTimestamp(uint32_t id); 1.443 + 1.444 + // Record timestamps for start and stop of an event. 1.445 + // In the stop method, the ID is only used in debug builds to test 1.446 + // correctness. 1.447 + void startEvent(uint32_t id); 1.448 + void stopEvent(uint32_t id); 1.449 + void stopEvent(); 1.450 + 1.451 + private: 1.452 + void assertNoQuotes(const char *text) { 1.453 +#ifdef DEBUG 1.454 + const char *quote = strchr(text, '"'); 1.455 + MOZ_ASSERT(!quote); 1.456 +#endif 1.457 + } 1.458 +#endif 1.459 +}; 1.460 + 1.461 +class TraceLogging 1.462 +{ 1.463 +#ifdef JS_TRACE_LOGGING 1.464 +#ifdef JS_THREADSAFE 1.465 + typedef HashMap<PRThread *, 1.466 + TraceLogger *, 1.467 + PointerHasher<PRThread *, 3>, 1.468 + SystemAllocPolicy> ThreadLoggerHashMap; 1.469 +#endif // JS_THREADSAFE 1.470 + typedef Vector<TraceLogger *, 1, js::SystemAllocPolicy > MainThreadLoggers; 1.471 + 1.472 + bool initialized; 1.473 + bool enabled; 1.474 + bool enabledTextIds[TraceLogger::LAST]; 1.475 + bool mainThreadEnabled; 1.476 + bool offThreadEnabled; 1.477 +#ifdef JS_THREADSAFE 1.478 + ThreadLoggerHashMap threadLoggers; 1.479 +#endif // JS_THREADSAFE 1.480 + MainThreadLoggers mainThreadLoggers; 1.481 + uint32_t loggerId; 1.482 + FILE *out; 1.483 + 1.484 + public: 1.485 + uint64_t startupTime; 1.486 +#ifdef JS_THREADSAFE 1.487 + PRLock *lock; 1.488 +#endif // JS_THREADSAFE 1.489 + 1.490 + TraceLogging(); 1.491 + ~TraceLogging(); 1.492 + 1.493 + TraceLogger *forMainThread(JSRuntime *runtime); 1.494 + TraceLogger *forMainThread(jit::CompileRuntime *runtime); 1.495 +#ifdef JS_THREADSAFE 1.496 + TraceLogger *forThread(PRThread *thread); 1.497 +#endif // JS_THREADSAFE 1.498 + 1.499 + bool isTextIdEnabled(uint32_t textId) { 1.500 + if (textId < TraceLogger::LAST) 1.501 + return enabledTextIds[textId]; 1.502 + return true; 1.503 + } 1.504 + 1.505 + private: 1.506 + TraceLogger *forMainThread(PerThreadData *mainThread); 1.507 + TraceLogger *create(); 1.508 + bool lazyInit(); 1.509 +#endif 1.510 +}; 1.511 + 1.512 +#ifdef JS_TRACE_LOGGING 1.513 +TraceLogger *TraceLoggerForMainThread(JSRuntime *runtime); 1.514 +TraceLogger *TraceLoggerForMainThread(jit::CompileRuntime *runtime); 1.515 +TraceLogger *TraceLoggerForCurrentThread(); 1.516 +#else 1.517 +inline TraceLogger *TraceLoggerForMainThread(JSRuntime *runtime) { 1.518 + return nullptr; 1.519 +}; 1.520 +inline TraceLogger *TraceLoggerForMainThread(jit::CompileRuntime *runtime) { 1.521 + return nullptr; 1.522 +}; 1.523 +inline TraceLogger *TraceLoggerForCurrentThread() { 1.524 + return nullptr; 1.525 +}; 1.526 +#endif 1.527 + 1.528 +inline bool TraceLoggerEnable(TraceLogger *logger) { 1.529 +#ifdef JS_TRACE_LOGGING 1.530 + if (logger) 1.531 + return logger->enable(); 1.532 +#endif 1.533 + return false; 1.534 +} 1.535 +inline bool TraceLoggerDisable(TraceLogger *logger) { 1.536 +#ifdef JS_TRACE_LOGGING 1.537 + if (logger) 1.538 + return logger->disable(); 1.539 +#endif 1.540 + return false; 1.541 +} 1.542 + 1.543 +inline uint32_t TraceLogCreateTextId(TraceLogger *logger, JSScript *script) { 1.544 +#ifdef JS_TRACE_LOGGING 1.545 + if (logger) 1.546 + return logger->createTextId(script); 1.547 +#endif 1.548 + return TraceLogger::TL_Error; 1.549 +} 1.550 +inline uint32_t TraceLogCreateTextId(TraceLogger *logger, 1.551 + const JS::ReadOnlyCompileOptions &compileOptions) 1.552 +{ 1.553 +#ifdef JS_TRACE_LOGGING 1.554 + if (logger) 1.555 + return logger->createTextId(compileOptions); 1.556 +#endif 1.557 + return TraceLogger::TL_Error; 1.558 +} 1.559 +inline uint32_t TraceLogCreateTextId(TraceLogger *logger, const char *text) { 1.560 +#ifdef JS_TRACE_LOGGING 1.561 + if (logger) 1.562 + return logger->createTextId(text); 1.563 +#endif 1.564 + return TraceLogger::TL_Error; 1.565 +} 1.566 +#ifdef JS_TRACE_LOGGING 1.567 +bool TraceLogTextIdEnabled(uint32_t textId); 1.568 +#else 1.569 +inline bool TraceLogTextIdEnabled(uint32_t textId) { 1.570 + return false; 1.571 +} 1.572 +#endif 1.573 +inline void TraceLogTimestamp(TraceLogger *logger, uint32_t textId) { 1.574 +#ifdef JS_TRACE_LOGGING 1.575 + if (logger) 1.576 + logger->logTimestamp(textId); 1.577 +#endif 1.578 +} 1.579 +inline void TraceLogStartEvent(TraceLogger *logger, uint32_t textId) { 1.580 +#ifdef JS_TRACE_LOGGING 1.581 + if (logger) 1.582 + logger->startEvent(textId); 1.583 +#endif 1.584 +} 1.585 +inline void TraceLogStopEvent(TraceLogger *logger, uint32_t textId) { 1.586 +#ifdef JS_TRACE_LOGGING 1.587 + if (logger) 1.588 + logger->stopEvent(textId); 1.589 +#endif 1.590 +} 1.591 +inline void TraceLogStopEvent(TraceLogger *logger) { 1.592 +#ifdef JS_TRACE_LOGGING 1.593 + if (logger) 1.594 + logger->stopEvent(); 1.595 +#endif 1.596 +} 1.597 + 1.598 +// Automatic logging at the start and end of function call. 1.599 +class AutoTraceLog { 1.600 +#ifdef JS_TRACE_LOGGING 1.601 + TraceLogger *logger; 1.602 + uint32_t textId; 1.603 + bool executed; 1.604 + AutoTraceLog *prev; 1.605 + 1.606 + public: 1.607 + AutoTraceLog(TraceLogger *logger, uint32_t textId MOZ_GUARD_OBJECT_NOTIFIER_PARAM) 1.608 + : logger(logger), 1.609 + textId(textId), 1.610 + executed(false) 1.611 + { 1.612 + MOZ_GUARD_OBJECT_NOTIFIER_INIT; 1.613 + if (logger) { 1.614 + TraceLogStartEvent(logger, textId); 1.615 + 1.616 + prev = logger->top; 1.617 + logger->top = this; 1.618 + } 1.619 + } 1.620 + 1.621 + ~AutoTraceLog() 1.622 + { 1.623 + if (logger) { 1.624 + while (this != logger->top) 1.625 + logger->top->stop(); 1.626 + stop(); 1.627 + } 1.628 + } 1.629 + private: 1.630 + void stop() { 1.631 + if (!executed) { 1.632 + executed = true; 1.633 + TraceLogStopEvent(logger, textId); 1.634 + } 1.635 + 1.636 + if (logger->top == this) 1.637 + logger->top = prev; 1.638 + } 1.639 +#else 1.640 + public: 1.641 + AutoTraceLog(TraceLogger *logger, uint32_t textId MOZ_GUARD_OBJECT_NOTIFIER_PARAM) 1.642 + { 1.643 + MOZ_GUARD_OBJECT_NOTIFIER_INIT; 1.644 + } 1.645 +#endif 1.646 + 1.647 + private: 1.648 + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER 1.649 +}; 1.650 + 1.651 +#ifdef JS_TRACE_LOGGING 1.652 +class AutoTraceLoggingLock 1.653 +{ 1.654 + TraceLogging *logging; 1.655 + 1.656 + public: 1.657 + AutoTraceLoggingLock(TraceLogging *logging MOZ_GUARD_OBJECT_NOTIFIER_PARAM) 1.658 + : logging(logging) 1.659 + { 1.660 + MOZ_GUARD_OBJECT_NOTIFIER_INIT; 1.661 +#ifdef JS_THREADSAFE 1.662 + PR_Lock(logging->lock); 1.663 +#endif // JS_THREADSAFE 1.664 + } 1.665 + ~AutoTraceLoggingLock() { 1.666 +#ifdef JS_THREADSAFE 1.667 + PR_Unlock(logging->lock); 1.668 +#endif // JS_THREADSAFE 1.669 + } 1.670 + private: 1.671 + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER 1.672 +}; 1.673 +#endif 1.674 + 1.675 +} /* namedata js */ 1.676 + 1.677 +#endif /* TraceLogging_h */