summaryrefslogtreecommitdiff
path: root/js/src/gc/GCTrace.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /js/src/gc/GCTrace.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloaduxp-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/gc/GCTrace.cpp')
-rw-r--r--js/src/gc/GCTrace.cpp243
1 files changed, 243 insertions, 0 deletions
diff --git a/js/src/gc/GCTrace.cpp b/js/src/gc/GCTrace.cpp
new file mode 100644
index 0000000000..5a336b0931
--- /dev/null
+++ b/js/src/gc/GCTrace.cpp
@@ -0,0 +1,243 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifdef JS_GC_TRACE
+
+#include "gc/GCTrace.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "gc/GCTraceFormat.h"
+
+#include "js/HashTable.h"
+
+using namespace js;
+using namespace js::gc;
+
+JS_STATIC_ASSERT(AllocKinds == unsigned(AllocKind::LIMIT));
+JS_STATIC_ASSERT(LastObjectAllocKind == unsigned(AllocKind::OBJECT_LAST));
+
+static FILE* gcTraceFile = nullptr;
+
+static HashSet<const Class*, DefaultHasher<const Class*>, SystemAllocPolicy> tracedClasses;
+static HashSet<const ObjectGroup*, DefaultHasher<const ObjectGroup*>, SystemAllocPolicy> tracedGroups;
+
+static inline void
+WriteWord(uint64_t data)
+{
+ if (gcTraceFile)
+ fwrite(&data, sizeof(data), 1, gcTraceFile);
+}
+
+static inline void
+TraceEvent(GCTraceEvent event, uint64_t payload = 0, uint8_t extra = 0)
+{
+ MOZ_ASSERT(event < GCTraceEventCount);
+ MOZ_ASSERT((payload >> TracePayloadBits) == 0);
+ WriteWord((uint64_t(event) << TraceEventShift) |
+ (uint64_t(extra) << TraceExtraShift) | payload);
+}
+
+static inline void
+TraceAddress(const void* p)
+{
+ TraceEvent(TraceDataAddress, uint64_t(p));
+}
+
+static inline void
+TraceInt(uint32_t data)
+{
+ TraceEvent(TraceDataInt, data);
+}
+
+static void
+TraceString(const char* string)
+{
+ JS_STATIC_ASSERT(sizeof(char) == 1);
+
+ size_t length = strlen(string);
+ const unsigned charsPerWord = sizeof(uint64_t);
+ unsigned wordCount = (length + charsPerWord - 1) / charsPerWord;
+
+ TraceEvent(TraceDataString, length);
+ for (unsigned i = 0; i < wordCount; ++i) {
+ union
+ {
+ uint64_t word;
+ char chars[charsPerWord];
+ } data;
+ strncpy(data.chars, string + (i * charsPerWord), charsPerWord);
+ WriteWord(data.word);
+ }
+}
+
+bool
+js::gc::InitTrace(GCRuntime& gc)
+{
+ /* This currently does not support multiple runtimes. */
+ MOZ_ALWAYS_TRUE(!gcTraceFile);
+
+ char* filename = getenv("JS_GC_TRACE");
+ if (!filename)
+ return true;
+
+ if (!tracedClasses.init() || !tracedTypes.init()) {
+ FinishTrace();
+ return false;
+ }
+
+ gcTraceFile = fopen(filename, "w");
+ if (!gcTraceFile) {
+ FinishTrace();
+ return false;
+ }
+
+ TraceEvent(TraceEventInit, 0, TraceFormatVersion);
+
+ /* Trace information about thing sizes. */
+ for (auto kind : AllAllocKinds())
+ TraceEvent(TraceEventThingSize, Arena::thingSize(kind));
+
+ return true;
+}
+
+void
+js::gc::FinishTrace()
+{
+ if (gcTraceFile) {
+ fclose(gcTraceFile);
+ gcTraceFile = nullptr;
+ }
+ tracedClasses.finish();
+ tracedTypes.finish();
+}
+
+bool
+js::gc::TraceEnabled()
+{
+ return gcTraceFile != nullptr;
+}
+
+void
+js::gc::TraceNurseryAlloc(Cell* thing, size_t size)
+{
+ if (thing) {
+ /* We don't have AllocKind here, but we can work it out from size. */
+ unsigned slots = (size - sizeof(JSObject)) / sizeof(JS::Value);
+ AllocKind kind = GetBackgroundAllocKind(GetGCObjectKind(slots));
+ TraceEvent(TraceEventNurseryAlloc, uint64_t(thing), kind);
+ }
+}
+
+void
+js::gc::TraceTenuredAlloc(Cell* thing, AllocKind kind)
+{
+ if (thing)
+ TraceEvent(TraceEventTenuredAlloc, uint64_t(thing), kind);
+}
+
+static void
+MaybeTraceClass(const Class* clasp)
+{
+ if (tracedClasses.has(clasp))
+ return;
+
+ TraceEvent(TraceEventClassInfo, uint64_t(clasp));
+ TraceString(clasp->name);
+ TraceInt(clasp->flags);
+ TraceInt(clasp->finalize != nullptr);
+
+ MOZ_ALWAYS_TRUE(tracedClasses.put(clasp));
+}
+
+static void
+MaybeTraceGroup(ObjectGroup* group)
+{
+ if (tracedGroups.has(group))
+ return;
+
+ MaybeTraceClass(group->clasp());
+ TraceEvent(TraceEventGroupInfo, uint64_t(group));
+ TraceAddress(group->clasp());
+ TraceInt(group->flags());
+
+ MOZ_ALWAYS_TRUE(tracedGroups.put(group));
+}
+
+void
+js::gc::TraceTypeNewScript(ObjectGroup* group)
+{
+ const size_t bufLength = 128;
+ static char buffer[bufLength];
+ MOZ_ASSERT(group->hasNewScript());
+ JSAtom* funName = group->newScript()->fun->displayAtom();
+ if (!funName)
+ return;
+
+ size_t length = funName->length();
+ MOZ_ALWAYS_TRUE(length < bufLength);
+ CopyChars(reinterpret_cast<Latin1Char*>(buffer), *funName);
+ buffer[length] = 0;
+
+ TraceEvent(TraceEventTypeNewScript, uint64_t(group));
+ TraceString(buffer);
+}
+
+void
+js::gc::TraceCreateObject(JSObject* object)
+{
+ if (!gcTraceFile)
+ return;
+
+ ObjectGroup* group = object->group();
+ MaybeTraceGroup(group);
+ TraceEvent(TraceEventCreateObject, uint64_t(object));
+ TraceAddress(group);
+}
+
+void
+js::gc::TraceMinorGCStart()
+{
+ TraceEvent(TraceEventMinorGCStart);
+}
+
+void
+js::gc::TracePromoteToTenured(Cell* src, Cell* dst)
+{
+ TraceEvent(TraceEventPromoteToTenured, uint64_t(src));
+ TraceAddress(dst);
+}
+
+void
+js::gc::TraceMinorGCEnd()
+{
+ TraceEvent(TraceEventMinorGCEnd);
+}
+
+void
+js::gc::TraceMajorGCStart()
+{
+ TraceEvent(TraceEventMajorGCStart);
+}
+
+void
+js::gc::TraceTenuredFinalize(Cell* thing)
+{
+ if (!gcTraceFile)
+ return;
+ if (thing->tenuredGetAllocKind() == AllocKind::OBJECT_GROUP)
+ tracedGroups.remove(static_cast<const ObjectGroup*>(thing));
+ TraceEvent(TraceEventTenuredFinalize, uint64_t(thing));
+}
+
+void
+js::gc::TraceMajorGCEnd()
+{
+ TraceEvent(TraceEventMajorGCEnd);
+}
+
+#endif