
# HG changeset patch
# User Hannes Verschore <hv1989@gmail.com>
# Date 1448912718 -3600
# Node ID 7683aae0caff682c97e21bbe0e6e40c0c958f7eb
# Parent  541a97a551cb7bdd2791e937b3cb2a087b0eab6f
Bug 1227028: TraceLogger - Fix when to keep the payload of a TraceLogger event, r=bbouvier

diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1247,16 +1247,18 @@ IonScript::Trace(JSTracer* trc, IonScrip
 void
 IonScript::Destroy(FreeOp* fop, IonScript* script)
 {
     if (script->pendingBuilder())
         jit::FinishOffThreadBuilder(nullptr, script->pendingBuilder());
 
     script->destroyCaches();
     script->unlinkFromRuntime(fop);
+    // Frees the potential event we have set.
+    script->traceLoggerScriptEvent_ = TraceLoggerEvent();
     fop->free_(script);
 }
 
 void
 IonScript::toggleBarriers(bool enabled)
 {
     method()->togglePreBarriers(enabled);
 }
diff --git a/js/src/vm/TraceLogging.cpp b/js/src/vm/TraceLogging.cpp
--- a/js/src/vm/TraceLogging.cpp
+++ b/js/src/vm/TraceLogging.cpp
@@ -344,33 +344,37 @@ TraceLoggerThread::extractScriptDetails(
     *lineno_len = *colno - *lineno - 1;
     *colno_len = strlen(*colno);
 }
 
 TraceLoggerEventPayload*
 TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId textId)
 {
     TextIdHashMap::AddPtr p = textIdPayloads.lookupForAdd(textId);
-    if (p)
+    if (p) {
+        MOZ_ASSERT(p->value()->textId() == textId); // Sanity check.
         return p->value();
+    }
 
     TraceLoggerEventPayload* payload = js_new<TraceLoggerEventPayload>(textId, (char*)nullptr);
 
     if (!textIdPayloads.add(p, textId, payload))
         return nullptr;
 
     return payload;
 }
 
 TraceLoggerEventPayload*
 TraceLoggerThread::getOrCreateEventPayload(const char* text)
 {
     PointerHashMap::AddPtr p = pointerMap.lookupForAdd((const void*)text);
-    if (p)
+    if (p) {
+        MOZ_ASSERT(p->value()->textId() < nextTextId); // Sanity check.
         return p->value();
+    }
 
     size_t len = strlen(text);
     char* str = js_pod_malloc<char>(len + 1);
     if (!str)
         return nullptr;
 
     DebugOnly<size_t> ret = JS_snprintf(str, len + 1, "%s", text);
     MOZ_ASSERT(ret == len);
@@ -412,18 +416,20 @@ TraceLoggerThread::getOrCreateEventPaylo
 
     // Only log scripts when enabled otherwise return the global Scripts textId,
     // which will get filtered out.
     MOZ_ASSERT(traceLoggerState);
     if (!traceLoggerState->isTextIdEnabled(type))
         return getOrCreateEventPayload(type);
 
     PointerHashMap::AddPtr p = pointerMap.lookupForAdd(ptr);
-    if (p)
+    if (p) {
+        MOZ_ASSERT(p->value()->textId() < nextTextId); // Sanity check.
         return p->value();
+    }
 
     // Compute the length of the string to create.
     size_t lenFilename = strlen(filename);
     size_t lenLineno = 1;
     for (size_t i = lineno; i /= 10; lenLineno++);
     size_t lenColno = 1;
     for (size_t i = colno; i /= 10; lenColno++);
 
@@ -561,17 +567,30 @@ TraceLoggerThread::log(uint32_t id)
             entryStart.time = start;
             entryStart.textId = TraceLogger_Internal;
 
             EventEntry& entryStop = events.pushUninitialized();
             entryStop.time = rdtsc() - traceLoggerState->startupTime;
             entryStop.textId = TraceLogger_Stop;
         }
 
-        // Free all TextEvents that have no uses anymore.
+        // Remove the item in the pointerMap for which the payloads
+        // have no uses anymore
+        for (PointerHashMap::Enum e(pointerMap); !e.empty(); e.popFront()) {
+            if (e.front().value()->uses() != 0)
+                continue;
+
+            TextIdHashMap::Ptr p = textIdPayloads.lookup(e.front().value()->textId());
+            MOZ_ASSERT(p);
+            textIdPayloads.remove(p);
+
+            e.removeFront();
+        }
+
+        // Free all payloads that have no uses anymore.
         for (TextIdHashMap::Enum e(textIdPayloads); !e.empty(); e.popFront()) {
             if (e.front().value()->uses() == 0) {
                 js_delete(e.front().value());
                 e.removeFront();
             }
         }
     }
 
@@ -992,8 +1011,21 @@ TraceLoggerEvent::TraceLoggerEvent(Trace
     }
 }
 
 TraceLoggerEvent::~TraceLoggerEvent()
 {
     if (payload_)
         payload_->release();
 }
+
+TraceLoggerEvent&
+TraceLoggerEvent::operator=(const TraceLoggerEvent& other)
+{
+    if (hasPayload())
+        payload()->release();
+    if (other.hasPayload())
+        other.payload()->use();
+
+    payload_ = other.payload_;
+
+    return *this;
+}
diff --git a/js/src/vm/TraceLogging.h b/js/src/vm/TraceLogging.h
--- a/js/src/vm/TraceLogging.h
+++ b/js/src/vm/TraceLogging.h
@@ -105,16 +105,19 @@ class TraceLoggerEvent {
 
     TraceLoggerEventPayload* payload() const {
         MOZ_ASSERT(hasPayload());
         return payload_;
     }
     bool hasPayload() const {
         return !!payload_;
     }
+
+    TraceLoggerEvent& operator=(const TraceLoggerEvent& other);
+    TraceLoggerEvent(const TraceLoggerEvent& event) = delete;
 };
 
 /**
  * An internal class holding the to-report string information, together with an
  * unique id and a useCount. Whenever this useCount reaches 0, this event
  * cannot get started/stopped anymore. Though consumers might still request the
  * to-report string information.
  */
@@ -125,16 +128,20 @@ class TraceLoggerEventPayload {
 
   public:
     TraceLoggerEventPayload(uint32_t textId, char* string)
       : textId_(textId),
         string_(string),
         uses_(0)
     { }
 
+    ~TraceLoggerEventPayload() {
+        MOZ_ASSERT(uses_ == 0);
+    }
+
     uint32_t textId() {
         return textId_;
     }
     const char* string() {
         return string_.get();
     }
     uint32_t uses() {
         return uses_;


