js/src/vm/TraceLogging.h

changeset 0
6474c204b198
     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 &current() {
   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 */

mercurial