fourthTier: It should be possible to record heap operations (both FastMalloc and JSC GC)
https://bugs.webkit.org/show_bug.cgi?id=116848
Source/JavaScriptCore:
Reviewed by Mark Hahnenberg.
Record GC heap operations if ENABLE(ALLOCATION_LOGGING).
* API/JSManagedValue.mm:
* dfg/DFGOperations.cpp:
* heap/Heap.cpp:
(JSC::Heap::collect):
* heap/Heap.h:
(Heap):
(JSC::Heap::allocateWithNormalDestructor):
(JSC::Heap::allocateWithImmortalStructureDestructor):
(JSC::Heap::allocateWithoutDestructor):
(JSC::Heap::tryAllocateStorage):
(JSC::Heap::tryReallocateStorage):
(JSC):
(JSC::Heap::ascribeOwner):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::append):
(JSC::SlotVisitor::internalAppend):
* heap/SlotVisitor.h:
(SlotVisitor):
* heap/SlotVisitorInlines.h:
(JSC::SlotVisitor::append):
(JSC::SlotVisitor::appendUnbarrieredPointer):
(JSC::SlotVisitor::appendUnbarrieredValue):
(JSC::SlotVisitor::appendUnbarrieredWeak):
(JSC::SlotVisitor::internalAppend):
(JSC):
(JSC::SlotVisitor::appendValues):
* jit/JITWriteBarrier.h:
(JSC::SlotVisitor::append):
* llint/LLIntCommon.h:
* runtime/Butterfly.h:
(Butterfly):
* runtime/ButterflyInlines.h:
(JSC::Butterfly::createUninitialized):
(JSC::Butterfly::create):
(JSC::Butterfly::growPropertyStorage):
(JSC::Butterfly::createOrGrowArrayRight):
(JSC):
(JSC::Butterfly::growArrayRight):
(JSC::Butterfly::resizeArray):
* runtime/JSArray.cpp:
(JSC::createArrayButterflyInDictionaryIndexingMode):
(JSC::JSArray::unshiftCountSlowCase):
* runtime/JSArray.h:
(JSC::createContiguousArrayButterfly):
(JSC::createArrayButterfly):
(JSC):
(JSC::JSArray::create):
(JSC::JSArray::tryCreateUninitialized):
* runtime/JSObject.cpp:
(JSC::JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists):
(JSC::JSObject::createInitialIndexedStorage):
(JSC::JSObject::createArrayStorage):
(JSC::JSObject::constructConvertedArrayStorageWithoutCopyingElements):
(JSC::JSObject::increaseVectorLength):
(JSC::JSObject::ensureLengthSlow):
(JSC::JSObject::growOutOfLineStorage):
* runtime/JSObject.h:
(JSC::JSObject::JSObject):
* runtime/Operations.h:
* runtime/RegExpMatchesArray.cpp:
(JSC::RegExpMatchesArray::create):
* runtime/StructureInlines.h:
(JSC):
* runtime/WriteBarrier.h:
(JSC):
Source/WTF:
Reviewed by Mark Hahnenberg.
* WTF.xcodeproj/project.pbxproj:
* wtf/DataLog.cpp:
(WTF):
(WTF::initializeLogFileOnce):
* wtf/FastMalloc.cpp:
(WTF::TCMalloc_ThreadCache::CreateCacheIfNecessary):
* wtf/Platform.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153189 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp
index 96ffbd6..9741cf5 100644
--- a/Source/JavaScriptCore/heap/Heap.cpp
+++ b/Source/JavaScriptCore/heap/Heap.cpp
@@ -702,6 +702,10 @@
void Heap::collect(SweepToggle sweepToggle)
{
+#if ENABLE(ALLOCATION_LOGGING)
+ dataLogF("JSC GC starting collection.\n");
+#endif
+
SamplingRegion samplingRegion("Garbage Collection");
RELEASE_ASSERT(!m_deferralDepth);
@@ -814,6 +818,10 @@
if (Options::showObjectStatistics())
HeapStatistics::showObjectStatistics(this);
+
+#if ENABLE(ALLOCATION_LOGGING)
+ dataLogF("JSC GC finishing collection.\n");
+#endif
}
bool Heap::collectIfNecessaryOrDefer()
diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h
index 6df105e..720a94a 100644
--- a/Source/JavaScriptCore/heap/Heap.h
+++ b/Source/JavaScriptCore/heap/Heap.h
@@ -119,8 +119,9 @@
MarkedAllocator& allocatorForObjectWithNormalDestructor(size_t bytes) { return m_objectSpace.normalDestructorAllocatorFor(bytes); }
MarkedAllocator& allocatorForObjectWithImmortalStructureDestructor(size_t bytes) { return m_objectSpace.immortalStructureDestructorAllocatorFor(bytes); }
CopiedAllocator& storageAllocator() { return m_storageSpace.allocator(); }
- CheckedBoolean tryAllocateStorage(size_t, void**);
- CheckedBoolean tryReallocateStorage(void**, size_t, size_t);
+ CheckedBoolean tryAllocateStorage(JSCell* intendedOwner, size_t, void**);
+ CheckedBoolean tryReallocateStorage(JSCell* intendedOwner, void**, size_t, size_t);
+ void ascribeOwner(JSCell* intendedOwner, void*);
typedef void (*Finalizer)(JSCell*);
JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer);
@@ -384,30 +385,64 @@
inline void* Heap::allocateWithNormalDestructor(size_t bytes)
{
+#if ENABLE(ALLOCATION_LOGGING)
+ dataLogF("JSC GC allocating %lu bytes with normal destructor.\n", bytes);
+#endif
ASSERT(isValidAllocation(bytes));
return m_objectSpace.allocateWithNormalDestructor(bytes);
}
inline void* Heap::allocateWithImmortalStructureDestructor(size_t bytes)
{
+#if ENABLE(ALLOCATION_LOGGING)
+ dataLogF("JSC GC allocating %lu bytes with immortal structure destructor.\n", bytes);
+#endif
ASSERT(isValidAllocation(bytes));
return m_objectSpace.allocateWithImmortalStructureDestructor(bytes);
}
inline void* Heap::allocateWithoutDestructor(size_t bytes)
{
+#if ENABLE(ALLOCATION_LOGGING)
+ dataLogF("JSC GC allocating %lu bytes without destructor.\n", bytes);
+#endif
ASSERT(isValidAllocation(bytes));
return m_objectSpace.allocateWithoutDestructor(bytes);
}
- inline CheckedBoolean Heap::tryAllocateStorage(size_t bytes, void** outPtr)
+ inline CheckedBoolean Heap::tryAllocateStorage(JSCell* intendedOwner, size_t bytes, void** outPtr)
{
- return m_storageSpace.tryAllocate(bytes, outPtr);
+ CheckedBoolean result = m_storageSpace.tryAllocate(bytes, outPtr);
+#if ENABLE(ALLOCATION_LOGGING)
+ dataLogF("JSC GC allocating %lu bytes of storage for %p: %p.\n", bytes, intendedOwner, *outPtr);
+#else
+ UNUSED_PARAM(intendedOwner);
+#endif
+ return result;
}
- inline CheckedBoolean Heap::tryReallocateStorage(void** ptr, size_t oldSize, size_t newSize)
+ inline CheckedBoolean Heap::tryReallocateStorage(JSCell* intendedOwner, void** ptr, size_t oldSize, size_t newSize)
{
- return m_storageSpace.tryReallocate(ptr, oldSize, newSize);
+#if ENABLE(ALLOCATION_LOGGING)
+ void* oldPtr = *ptr;
+#endif
+ CheckedBoolean result = m_storageSpace.tryReallocate(ptr, oldSize, newSize);
+#if ENABLE(ALLOCATION_LOGGING)
+ dataLogF("JSC GC reallocating %lu -> %lu bytes of storage for %p: %p -> %p.\n", oldSize, newSize, intendedOwner, oldPtr, *ptr);
+#else
+ UNUSED_PARAM(intendedOwner);
+#endif
+ return result;
+ }
+
+ inline void Heap::ascribeOwner(JSCell* intendedOwner, void* storage)
+ {
+#if ENABLE(ALLOCATION_LOGGING)
+ dataLogF("JSC GC ascribing %p as owner of storage %p.\n", intendedOwner, storage);
+#else
+ UNUSED_PARAM(intendedOwner);
+ UNUSED_PARAM(storage);
+#endif
}
inline BlockAllocator& Heap::blockAllocator()
diff --git a/Source/JavaScriptCore/heap/SlotVisitor.cpp b/Source/JavaScriptCore/heap/SlotVisitor.cpp
index 6c2ded0..f0d5e57 100644
--- a/Source/JavaScriptCore/heap/SlotVisitor.cpp
+++ b/Source/JavaScriptCore/heap/SlotVisitor.cpp
@@ -65,7 +65,7 @@
JSCell** roots = conservativeRoots.roots();
size_t size = conservativeRoots.size();
for (size_t i = 0; i < size; ++i)
- internalAppend(roots[i]);
+ internalAppend(0, roots[i]);
}
ALWAYS_INLINE static void visitChildren(SlotVisitor& visitor, const JSCell* cell)
@@ -279,7 +279,7 @@
return ((length() > 1) && !isRope() && !isHashConsSingleton());
}
-ALWAYS_INLINE void SlotVisitor::internalAppend(JSValue* slot)
+ALWAYS_INLINE void SlotVisitor::internalAppend(void* from, JSValue* slot)
{
// This internalAppend is only intended for visits to object and array backing stores.
// as it can change the JSValue pointed to be the argument when the original JSValue
@@ -316,7 +316,7 @@
}
}
- internalAppend(cell);
+ internalAppend(from, cell);
}
void SlotVisitor::harvestWeakReferences()
diff --git a/Source/JavaScriptCore/heap/SlotVisitor.h b/Source/JavaScriptCore/heap/SlotVisitor.h
index e1808fa..b596e2d 100644
--- a/Source/JavaScriptCore/heap/SlotVisitor.h
+++ b/Source/JavaScriptCore/heap/SlotVisitor.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -106,10 +106,10 @@
void append(JSValue*);
void append(JSValue*, size_t count);
void append(JSCell**);
-
- void internalAppend(JSCell*);
- void internalAppend(JSValue);
- void internalAppend(JSValue*);
+
+ void internalAppend(void* from, JSCell*);
+ void internalAppend(void* from, JSValue);
+ void internalAppend(void* from, JSValue*);
JS_EXPORT_PRIVATE void mergeOpaqueRoots();
void mergeOpaqueRootsIfNecessary();
diff --git a/Source/JavaScriptCore/heap/SlotVisitorInlines.h b/Source/JavaScriptCore/heap/SlotVisitorInlines.h
index 4273a28..e308dd4 100644
--- a/Source/JavaScriptCore/heap/SlotVisitorInlines.h
+++ b/Source/JavaScriptCore/heap/SlotVisitorInlines.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -39,7 +39,7 @@
{
for (size_t i = 0; i < count; ++i) {
JSValue& value = slot[i];
- internalAppend(value);
+ internalAppend(&value, value);
}
}
@@ -48,25 +48,25 @@
{
ASSERT(slot);
JSCell* cell = *slot;
- internalAppend(cell);
+ internalAppend(slot, cell);
}
ALWAYS_INLINE void SlotVisitor::append(JSValue* slot)
{
ASSERT(slot);
- internalAppend(*slot);
+ internalAppend(slot, *slot);
}
ALWAYS_INLINE void SlotVisitor::appendUnbarrieredValue(JSValue* slot)
{
ASSERT(slot);
- internalAppend(*slot);
+ internalAppend(slot, *slot);
}
ALWAYS_INLINE void SlotVisitor::append(JSCell** slot)
{
ASSERT(slot);
- internalAppend(*slot);
+ internalAppend(slot, *slot);
}
template<typename T>
@@ -74,14 +74,50 @@
{
ASSERT(weak);
if (weak->get())
- internalAppend(weak->get());
+ internalAppend(0, weak->get());
}
-ALWAYS_INLINE void SlotVisitor::internalAppend(JSValue value)
+ALWAYS_INLINE void SlotVisitor::internalAppend(void* from, JSValue value)
{
if (!value || !value.isCell())
return;
- internalAppend(value.asCell());
+ internalAppend(from, value.asCell());
+}
+
+ALWAYS_INLINE void SlotVisitor::internalAppend(void* from, JSCell* cell)
+{
+ ASSERT(!m_isCheckingForDefaultMarkViolation);
+ if (!cell)
+ return;
+#if ENABLE(ALLOCATION_LOGGING)
+ dataLogF("JSC GC noticing reference from %p to %p.\n", from, cell);
+#else
+ UNUSED_PARAM(from);
+#endif
+#if ENABLE(GC_VALIDATION)
+ validate(cell);
+#endif
+ if (Heap::testAndSetMarked(cell) || !cell->structure())
+ return;
+
+ m_visitCount++;
+
+ MARK_LOG_CHILD(*this, cell);
+
+ // Should never attempt to mark something that is zapped.
+ ASSERT(!cell->isZapped());
+
+ m_stack.append(cell);
+}
+
+template<typename T> inline void SlotVisitor::append(WriteBarrierBase<T>* slot)
+{
+ internalAppend(slot, *slot->slot());
+}
+
+ALWAYS_INLINE void SlotVisitor::appendValues(WriteBarrierBase<Unknown>* barriers, size_t count)
+{
+ append(barriers->slot(), count);
}
inline void SlotVisitor::addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester)