fourthTier: It should be possible to record heap operations (both FastMalloc and...
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Jul 2013 04:01:20 +0000 (04:01 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Jul 2013 04:01:20 +0000 (04:01 +0000)
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

24 files changed:
Source/JavaScriptCore/API/JSManagedValue.mm
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/Heap.h
Source/JavaScriptCore/heap/SlotVisitor.cpp
Source/JavaScriptCore/heap/SlotVisitor.h
Source/JavaScriptCore/heap/SlotVisitorInlines.h
Source/JavaScriptCore/jit/JITWriteBarrier.h
Source/JavaScriptCore/llint/LLIntCommon.h
Source/JavaScriptCore/runtime/Butterfly.h
Source/JavaScriptCore/runtime/ButterflyInlines.h
Source/JavaScriptCore/runtime/JSArray.cpp
Source/JavaScriptCore/runtime/JSArray.h
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/Operations.h
Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
Source/JavaScriptCore/runtime/StructureInlines.h
Source/JavaScriptCore/runtime/WriteBarrier.h
Source/WTF/ChangeLog
Source/WTF/wtf/DataLog.cpp
Source/WTF/wtf/FastMalloc.cpp
Source/WTF/wtf/Platform.h

index f336ba6..758082f 100644 (file)
 
 #import "APICast.h"
 #import "Heap.h"
-#import "JSCJSValueInlines.h"
 #import "JSContextInternal.h"
 #import "JSValueInternal.h"
 #import "Weak.h"
 #import "WeakHandleOwner.h"
 #import "ObjcRuntimeExtras.h"
+#import "Operations.h"
 
 class JSManagedValueHandleOwner : public JSC::WeakHandleOwner {
 public:
index 5fda9ec..2eb4112 100644 (file)
@@ -1,5 +1,80 @@
 2013-05-27  Filip Pizlo  <fpizlo@apple.com>
 
+        It should be possible to record heap operations (both FastMalloc and JSC GC)
+        https://bugs.webkit.org/show_bug.cgi?id=116848
+
+        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):
+
+2013-05-27  Filip Pizlo  <fpizlo@apple.com>
+
         testRunner should be able to tell you if a function is DFG compiled
         https://bugs.webkit.org/show_bug.cgi?id=116847
 
index baf11e8..c4c19a5 100644 (file)
@@ -1486,7 +1486,7 @@ char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecStat
     NativeCallFrameTracer tracer(&vm, exec);
 
     return reinterpret_cast<char*>(
-        Butterfly::createUninitialized(vm, 0, initialOutOfLineCapacity, false, 0));
+        Butterfly::createUninitialized(vm, 0, 0, initialOutOfLineCapacity, false, 0));
 }
 
 char* DFG_OPERATION operationAllocatePropertyStorage(ExecState* exec, size_t newSize)
@@ -1495,7 +1495,7 @@ char* DFG_OPERATION operationAllocatePropertyStorage(ExecState* exec, size_t new
     NativeCallFrameTracer tracer(&vm, exec);
 
     return reinterpret_cast<char*>(
-        Butterfly::createUninitialized(vm, 0, newSize, false, 0));
+        Butterfly::createUninitialized(vm, 0, 0, newSize, false, 0));
 }
 
 char* DFG_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState* exec, JSObject* object)
index 96ffbd6..9741cf5 100644 (file)
@@ -702,6 +702,10 @@ static double minute = 60.0;
 
 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 @@ void Heap::collect(SweepToggle sweepToggle)
 
     if (Options::showObjectStatistics())
         HeapStatistics::showObjectStatistics(this);
+
+#if ENABLE(ALLOCATION_LOGGING)
+    dataLogF("JSC GC finishing collection.\n");
+#endif
 }
 
 bool Heap::collectIfNecessaryOrDefer()
index 6df105e..720a94a 100644 (file)
@@ -119,8 +119,9 @@ namespace JSC {
         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 @@ namespace JSC {
 
     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()
index 6c2ded0..f0d5e57 100644 (file)
@@ -65,7 +65,7 @@ void SlotVisitor::append(ConservativeRoots& conservativeRoots)
     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 @@ ALWAYS_INLINE bool JSString::shouldTryHashCons()
     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 @@ ALWAYS_INLINE void SlotVisitor::internalAppend(JSValue* slot)
         }
     }
 
-    internalAppend(cell);
+    internalAppend(from, cell);
 }
 
 void SlotVisitor::harvestWeakReferences()
index e1808fa..b596e2d 100644 (file)
@@ -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 @@ private:
     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();
index 4273a28..e308dd4 100644 (file)
@@ -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 @@ ALWAYS_INLINE void SlotVisitor::append(JSValue* slot, size_t count)
 {
     for (size_t i = 0; i < count; ++i) {
         JSValue& value = slot[i];
-        internalAppend(value);
+        internalAppend(&value, value);
     }
 }
 
@@ -48,25 +48,25 @@ inline void SlotVisitor::appendUnbarrieredPointer(T** slot)
 {
     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 @@ ALWAYS_INLINE void SlotVisitor::appendUnbarrieredWeak(Weak<T>* weak)
 {
     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)
index 9da1ea7..ca2ca6e 100644 (file)
@@ -137,7 +137,7 @@ public:
 
 template<typename T> inline void SlotVisitor::append(JITWriteBarrier<T>* slot)
 {
-    internalAppend(slot->get());
+    internalAppend(0, slot->get());
 }
 
 }
index 1797ff0..61ffe18 100644 (file)
@@ -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
 
 // Disable inline allocation in the interpreter. This is great if you're changing
 // how the GC allocates.
+#if ENABLE(ALLOCATION_LOGGING)
+#define LLINT_ALWAYS_ALLOCATE_SLOW 1
+#else
 #define LLINT_ALWAYS_ALLOCATE_SLOW 0
+#endif
 
 // Disable inline caching of get_by_id and put_by_id.
 #define LLINT_ALWAYS_ACCESS_SLOW 0
@@ -42,7 +46,7 @@
 // Enable OSR into the JIT. Disabling this while the LLInt is enabled effectively
 // turns off all JIT'ing, since in LLInt's parlance, OSR subsumes any form of JIT
 // invocation.
-#if ENABLE(JIT)
+#if ENABLE(JIT) && !ENABLE(ALLOCATION_LOGGING)
 #define LLINT_OSR_TO_JIT 1
 #else
 #define LLINT_OSR_TO_JIT 0
index eb6d82a..3fc0077 100644 (file)
@@ -104,10 +104,10 @@ public:
     static ptrdiff_t offsetOfPublicLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfPublicLength(); }
     static ptrdiff_t offsetOfVectorLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfVectorLength(); }
     
-    static Butterfly* createUninitialized(VM&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes);
+    static Butterfly* createUninitialized(VM&, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes);
 
-    static Butterfly* create(VM&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader&, size_t indexingPayloadSizeInBytes);
-    static Butterfly* create(VM&, Structure*);
+    static Butterfly* create(VM&, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader&, size_t indexingPayloadSizeInBytes);
+    static Butterfly* create(VM&, JSCell* intendedOwner, Structure*);
     static Butterfly* createUninitializedDuringCollection(CopyVisitor&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes);
     
     IndexingHeader* indexingHeader() { return IndexingHeader::from(this); }
@@ -147,20 +147,23 @@ public:
     void* base(size_t preCapacity, size_t propertyCapacity) { return propertyStorage() - propertyCapacity - preCapacity; }
     void* base(Structure*);
 
-    static Butterfly* createOrGrowArrayRight(Butterfly*, VM&, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); 
+    static Butterfly* createOrGrowArrayRight(
+        Butterfly*, VM&, JSCell* intendedOwner, Structure* oldStructure,
+        size_t propertyCapacity, bool hadIndexingHeader,
+        size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); 
 
     // The butterfly reallocation methods perform the reallocation itself but do not change any
     // of the meta-data to reflect that the reallocation occurred. Note that this set of
     // methods is not exhaustive and is not intended to encapsulate all possible allocation
     // modes of butterflies - there are code paths that allocate butterflies by calling
     // directly into Heap::tryAllocateStorage.
-    Butterfly* growPropertyStorage(VM&, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity);
-    Butterfly* growPropertyStorage(VM&, Structure* oldStructure, size_t oldPropertyCapacity, size_t newPropertyCapacity);
-    Butterfly* growPropertyStorage(VM&, Structure* oldStructure, size_t newPropertyCapacity);
-    Butterfly* growArrayRight(VM&, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // Assumes that preCapacity is zero, and asserts as much.
-    Butterfly* growArrayRight(VM&, Structure*, size_t newIndexingPayloadSizeInBytes);
-    Butterfly* resizeArray(VM&, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes);
-    Butterfly* resizeArray(VM&, Structure*, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes); // Assumes that you're not changing whether or not the object has an indexing header.
+    Butterfly* growPropertyStorage(VM&, JSCell* intendedOwner, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity);
+    Butterfly* growPropertyStorage(VM&, JSCell* intendedOwner, Structure* oldStructure, size_t oldPropertyCapacity, size_t newPropertyCapacity);
+    Butterfly* growPropertyStorage(VM&, JSCell* intendedOwner, Structure* oldStructure, size_t newPropertyCapacity);
+    Butterfly* growArrayRight(VM&, JSCell* intendedOwner, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // Assumes that preCapacity is zero, and asserts as much.
+    Butterfly* growArrayRight(VM&, JSCell* intendedOwner, Structure*, size_t newIndexingPayloadSizeInBytes);
+    Butterfly* resizeArray(VM&, JSCell* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes);
+    Butterfly* resizeArray(VM&, JSCell* intendedOwner, Structure*, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes); // Assumes that you're not changing whether or not the object has an indexing header.
     Butterfly* unshift(Structure*, size_t numberOfSlots);
     Butterfly* shift(Structure*, size_t numberOfSlots);
 };
index a0e2af1..44f23b6 100644 (file)
 
 namespace JSC {
 
-inline Butterfly* Butterfly::createUninitialized(VM& vm, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
+inline Butterfly* Butterfly::createUninitialized(VM& vm, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
 {
     void* temp;
     size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
-    RELEASE_ASSERT(vm.heap.tryAllocateStorage(size, &temp));
+    RELEASE_ASSERT(vm.heap.tryAllocateStorage(intendedOwner, size, &temp));
     Butterfly* result = fromBase(temp, preCapacity, propertyCapacity);
     return result;
 }
 
-inline Butterfly* Butterfly::create(VM& vm, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes)
+inline Butterfly* Butterfly::create(VM& vm, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes)
 {
     Butterfly* result = createUninitialized(
-        vm, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
+        vm, intendedOwner, preCapacity, propertyCapacity, hasIndexingHeader,
+        indexingPayloadSizeInBytes);
     if (hasIndexingHeader)
         *result->indexingHeader() = indexingHeader;
     return result;
 }
 
-inline Butterfly* Butterfly::create(VM& vm, Structure* structure)
+inline Butterfly* Butterfly::create(VM& vm, JSCell* intendedOwner, Structure* structure)
 {
-    return create(vm, 0, structure->outOfLineCapacity(), hasIndexingHeader(structure->indexingType()), IndexingHeader(), 0);
+    return create(
+        vm, intendedOwner, 0, structure->outOfLineCapacity(),
+        hasIndexingHeader(structure->indexingType()), IndexingHeader(), 0);
 }
 
 inline Butterfly* Butterfly::createUninitializedDuringCollection(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
@@ -72,11 +75,14 @@ inline void* Butterfly::base(Structure* structure)
     return base(indexingHeader()->preCapacity(structure), structure->outOfLineCapacity());
 }
 
-inline Butterfly* Butterfly::growPropertyStorage(VM& vm, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity)
+inline Butterfly* Butterfly::growPropertyStorage(
+    VM& vm, JSCell* intendedOwner, size_t preCapacity, size_t oldPropertyCapacity,
+    bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity)
 {
     RELEASE_ASSERT(newPropertyCapacity > oldPropertyCapacity);
     Butterfly* result = createUninitialized(
-        vm, preCapacity, newPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
+        vm, intendedOwner, preCapacity, newPropertyCapacity, hasIndexingHeader,
+        indexingPayloadSizeInBytes);
     memcpy(
         result->propertyStorage() - oldPropertyCapacity,
         propertyStorage() - oldPropertyCapacity,
@@ -84,51 +90,72 @@ inline Butterfly* Butterfly::growPropertyStorage(VM& vm, size_t preCapacity, siz
     return result;
 }
 
-inline Butterfly* Butterfly::growPropertyStorage(VM& vm, Structure* structure, size_t oldPropertyCapacity, size_t newPropertyCapacity)
+inline Butterfly* Butterfly::growPropertyStorage(
+    VM& vm, JSCell* intendedOwner, Structure* structure, size_t oldPropertyCapacity,
+    size_t newPropertyCapacity)
 {
     return growPropertyStorage(
-        vm, indexingHeader()->preCapacity(structure), oldPropertyCapacity,
+        vm, intendedOwner, indexingHeader()->preCapacity(structure), oldPropertyCapacity,
         hasIndexingHeader(structure->indexingType()),
         indexingHeader()->indexingPayloadSizeInBytes(structure), newPropertyCapacity);
 }
 
-inline Butterfly* Butterfly::growPropertyStorage(VM& vm, Structure* oldStructure, size_t newPropertyCapacity)
+inline Butterfly* Butterfly::growPropertyStorage(
+    VM& vm, JSCell* intendedOwner, Structure* oldStructure, size_t newPropertyCapacity)
 {
     return growPropertyStorage(
-        vm, oldStructure, oldStructure->outOfLineCapacity(), newPropertyCapacity);
+        vm, intendedOwner, oldStructure, oldStructure->outOfLineCapacity(),
+        newPropertyCapacity);
 }
 
-inline Butterfly* Butterfly::createOrGrowArrayRight(Butterfly* oldButterfly, VM& vm, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes)
+inline Butterfly* Butterfly::createOrGrowArrayRight(
+    Butterfly* oldButterfly, VM& vm, JSCell* intendedOwner, Structure* oldStructure,
+    size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes,
+    size_t newIndexingPayloadSizeInBytes)
 {
-    if (!oldButterfly)
-        return create(vm, 0, propertyCapacity, true, IndexingHeader(), newIndexingPayloadSizeInBytes);
-    return oldButterfly->growArrayRight(vm, oldStructure, propertyCapacity, hadIndexingHeader, oldIndexingPayloadSizeInBytes, newIndexingPayloadSizeInBytes);
+    if (!oldButterfly) {
+        return create(
+            vm, intendedOwner, 0, propertyCapacity, true, IndexingHeader(),
+            newIndexingPayloadSizeInBytes);
+    }
+    return oldButterfly->growArrayRight(
+        vm, intendedOwner, oldStructure, propertyCapacity, hadIndexingHeader,
+        oldIndexingPayloadSizeInBytes, newIndexingPayloadSizeInBytes);
 }
 
-inline Butterfly* Butterfly::growArrayRight(VM& vm, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes)
+inline Butterfly* Butterfly::growArrayRight(
+    VM& vm, JSCell* intendedOwner, Structure* oldStructure, size_t propertyCapacity,
+    bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes,
+    size_t newIndexingPayloadSizeInBytes)
 {
     ASSERT_UNUSED(oldStructure, !indexingHeader()->preCapacity(oldStructure));
     ASSERT_UNUSED(oldStructure, hadIndexingHeader == hasIndexingHeader(oldStructure->indexingType()));
     void* theBase = base(0, propertyCapacity);
     size_t oldSize = totalSize(0, propertyCapacity, hadIndexingHeader, oldIndexingPayloadSizeInBytes);
     size_t newSize = totalSize(0, propertyCapacity, true, newIndexingPayloadSizeInBytes);
-    if (!vm.heap.tryReallocateStorage(&theBase, oldSize, newSize))
+    if (!vm.heap.tryReallocateStorage(intendedOwner, &theBase, oldSize, newSize))
         return 0;
     return fromBase(theBase, 0, propertyCapacity);
 }
 
-inline Butterfly* Butterfly::growArrayRight(VM& vm, Structure* oldStructure, size_t newIndexingPayloadSizeInBytes)
+inline Butterfly* Butterfly::growArrayRight(
+    VM& vm, JSCell* intendedOwner, Structure* oldStructure,
+    size_t newIndexingPayloadSizeInBytes)
 {
     return growArrayRight(
-        vm, oldStructure, oldStructure->outOfLineCapacity(),
+        vm, intendedOwner, oldStructure, oldStructure->outOfLineCapacity(),
         hasIndexingHeader(oldStructure->indexingType()),
         indexingHeader()->indexingPayloadSizeInBytes(oldStructure), newIndexingPayloadSizeInBytes);
 }
 
-inline Butterfly* Butterfly::resizeArray(VM& vm, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes)
+inline Butterfly* Butterfly::resizeArray(
+    VM& vm, JSCell* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader,
+    size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader,
+    size_t newIndexingPayloadSizeInBytes)
 {
     Butterfly* result = createUninitialized(
-        vm, newPreCapacity, propertyCapacity, newHasIndexingHeader, newIndexingPayloadSizeInBytes);
+        vm, intendedOwner, newPreCapacity, propertyCapacity, newHasIndexingHeader,
+        newIndexingPayloadSizeInBytes);
     // FIXME: This could be made much more efficient if we used the property size,
     // not the capacity.
     void* to = result->propertyStorage() - propertyCapacity;
@@ -140,11 +167,13 @@ inline Butterfly* Butterfly::resizeArray(VM& vm, size_t propertyCapacity, bool o
     return result;
 }
 
-inline Butterfly* Butterfly::resizeArray(VM& vm, Structure* structure, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes)
+inline Butterfly* Butterfly::resizeArray(
+    VM& vm, JSCell* intendedOwner, Structure* structure, size_t newPreCapacity,
+    size_t newIndexingPayloadSizeInBytes)
 {
     bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType());
     return resizeArray(
-        vm, structure->outOfLineCapacity(), hasIndexingHeader,
+        vm, intendedOwner, structure->outOfLineCapacity(), hasIndexingHeader,
         indexingHeader()->indexingPayloadSizeInBytes(structure), newPreCapacity,
         hasIndexingHeader, newIndexingPayloadSizeInBytes);
 }
index f97cced..b3df4ab 100644 (file)
@@ -48,10 +48,11 @@ ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSArray);
 
 const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSArray)};
 
-Butterfly* createArrayButterflyInDictionaryIndexingMode(VM& vm, unsigned initialLength)
+Butterfly* createArrayButterflyInDictionaryIndexingMode(
+    VM& vm, JSCell* intendedOwner, unsigned initialLength)
 {
     Butterfly* butterfly = Butterfly::create(
-        vm, 0, 0, true, IndexingHeader(), ArrayStorage::sizeFor(0));
+        vm, intendedOwner, 0, 0, true, IndexingHeader(), ArrayStorage::sizeFor(0));
     ArrayStorage* storage = butterfly->arrayStorage();
     storage->setLength(initialLength);
     storage->setVectorLength(0);
@@ -286,7 +287,7 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count)
         newStorageCapacity = currentCapacity;
     } else {
         size_t newSize = Butterfly::totalSize(0, propertyCapacity, true, ArrayStorage::sizeFor(desiredCapacity));
-        if (!vm.heap.tryAllocateStorage(newSize, &newAllocBase))
+        if (!vm.heap.tryAllocateStorage(this, newSize, &newAllocBase))
             return false;
         newStorageCapacity = desiredCapacity;
     }
index af81d2e..6da3397 100644 (file)
@@ -174,21 +174,22 @@ private:
     void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength);
 };
 
-inline Butterfly* createContiguousArrayButterfly(VM& vm, unsigned length, unsigned& vectorLength)
+inline Butterfly* createContiguousArrayButterfly(VM& vm, JSCell* intendedOwner, unsigned length, unsigned& vectorLength)
 {
     IndexingHeader header;
     vectorLength = std::max(length, BASE_VECTOR_LEN);
     header.setVectorLength(vectorLength);
     header.setPublicLength(length);
     Butterfly* result = Butterfly::create(
-        vm, 0, 0, true, header, vectorLength * sizeof(EncodedJSValue));
+        vm, intendedOwner, 0, 0, true, header, vectorLength * sizeof(EncodedJSValue));
     return result;
 }
 
-inline Butterfly* createArrayButterfly(VM& vm, unsigned initialLength)
+inline Butterfly* createArrayButterfly(VM& vm, JSCell* intendedOwner, unsigned initialLength)
 {
     Butterfly* butterfly = Butterfly::create(
-        vm, 0, 0, true, baseIndexingHeaderForArray(initialLength), ArrayStorage::sizeFor(BASE_VECTOR_LEN));
+        vm, intendedOwner, 0, 0, true, baseIndexingHeaderForArray(initialLength),
+        ArrayStorage::sizeFor(BASE_VECTOR_LEN));
     ArrayStorage* storage = butterfly->arrayStorage();
     storage->m_indexBias = 0;
     storage->m_sparseMap.clear();
@@ -196,7 +197,8 @@ inline Butterfly* createArrayButterfly(VM& vm, unsigned initialLength)
     return butterfly;
 }
 
-Butterfly* createArrayButterflyInDictionaryIndexingMode(VM&, unsigned initialLength);
+Butterfly* createArrayButterflyInDictionaryIndexingMode(
+    VM&, JSCell* intendedOwner, unsigned initialLength);
 
 inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLength)
 {
@@ -208,7 +210,7 @@ inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLe
             || hasDouble(structure->indexingType())
             || hasContiguous(structure->indexingType()));
         unsigned vectorLength;
-        butterfly = createContiguousArrayButterfly(vm, initialLength, vectorLength);
+        butterfly = createContiguousArrayButterfly(vm, 0, initialLength, vectorLength);
         ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX);
         if (hasDouble(structure->indexingType())) {
             for (unsigned i = 0; i < vectorLength; ++i)
@@ -218,7 +220,7 @@ inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLe
         ASSERT(
             structure->indexingType() == ArrayWithSlowPutArrayStorage
             || structure->indexingType() == ArrayWithArrayStorage);
-        butterfly = createArrayButterfly(vm, initialLength);
+        butterfly = createArrayButterfly(vm, 0, initialLength);
     }
     JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap)) JSArray(vm, structure, butterfly);
     array->finishCreation(vm);
@@ -240,7 +242,7 @@ inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, un
             || hasContiguous(structure->indexingType()));
 
         void* temp;
-        if (!vm.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp))
+        if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp))
             return 0;
         butterfly = Butterfly::fromBase(temp, 0, 0);
         butterfly->setVectorLength(vectorLength);
@@ -251,7 +253,7 @@ inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, un
         }
     } else {
         void* temp;
-        if (!vm.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp))
+        if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp))
             return 0;
         butterfly = Butterfly::fromBase(temp, 0, 0);
         *butterfly->indexingHeader() = indexingHeaderForArray(initialLength, vectorLength);
index 2f1f274..40eda92 100644 (file)
@@ -543,7 +543,7 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists
             map->add(this, i).iterator->value.set(vm, this, value);
     }
 
-    Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, structure(), 0, ArrayStorage::sizeFor(0));
+    Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, this, structure(), 0, ArrayStorage::sizeFor(0));
     RELEASE_ASSERT(newButterfly);
     
     m_butterfly = newButterfly;
@@ -596,8 +596,8 @@ Butterfly* JSObject::createInitialIndexedStorage(VM& vm, unsigned length, size_t
     ASSERT(!structure()->needsSlowPutIndexing());
     ASSERT(!indexingShouldBeSparse());
     unsigned vectorLength = std::max(length, BASE_VECTOR_LEN);
-    Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(m_butterfly, 
-        vm, structure(), structure()->outOfLineCapacity(), false, 0,
+    Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
+        m_butterfly, vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
         elementSize * vectorLength);
     newButterfly->setPublicLength(length);
     newButterfly->setVectorLength(vectorLength);
@@ -642,8 +642,8 @@ ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vec
 {
     IndexingType oldType = structure()->indexingType();
     ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
-    Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(m_butterfly, 
-        vm, structure(), structure()->outOfLineCapacity(), false, 0,
+    Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
+        m_butterfly, vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
         ArrayStorage::sizeFor(vectorLength));
     RELEASE_ASSERT(newButterfly);
 
@@ -695,7 +695,7 @@ ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(VM&
     unsigned propertySize = structure()->outOfLineSize();
     
     Butterfly* newButterfly = Butterfly::createUninitialized(
-        vm, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
+        vm, this, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
     
     memcpy(
         newButterfly->propertyStorage() - propertySize,
@@ -2310,7 +2310,9 @@ bool JSObject::increaseVectorLength(VM& vm, unsigned newLength)
 
     // Fast case - there is no precapacity. In these cases a realloc makes sense.
     if (LIKELY(!indexBias)) {
-        Butterfly* newButterfly = storage->butterfly()->growArrayRight(vm, structure(), structure()->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength), ArrayStorage::sizeFor(newVectorLength));
+        Butterfly* newButterfly = storage->butterfly()->growArrayRight(
+            vm, this, structure(), structure()->outOfLineCapacity(), true,
+            ArrayStorage::sizeFor(vectorLength), ArrayStorage::sizeFor(newVectorLength));
         if (!newButterfly)
             return false;
         m_butterfly = newButterfly;
@@ -2321,7 +2323,7 @@ bool JSObject::increaseVectorLength(VM& vm, unsigned newLength)
     // Remove some, but not all of the precapacity. Atomic decay, & capped to not overflow array length.
     unsigned newIndexBias = std::min(indexBias >> 1, MAX_STORAGE_VECTOR_LENGTH - newVectorLength);
     Butterfly* newButterfly = storage->butterfly()->resizeArray(
-        vm,
+        vm, this,
         structure()->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength),
         newIndexBias, true, ArrayStorage::sizeFor(newVectorLength));
     if (!newButterfly)
@@ -2344,7 +2346,7 @@ void JSObject::ensureLengthSlow(VM& vm, unsigned length)
         MAX_STORAGE_VECTOR_LENGTH);
     unsigned oldVectorLength = m_butterfly->vectorLength();
     m_butterfly = m_butterfly->growArrayRight(
-        vm, structure(), structure()->outOfLineCapacity(), true,
+        vm, this, structure(), structure()->outOfLineCapacity(), true,
         oldVectorLength * sizeof(EncodedJSValue),
         newVectorLength * sizeof(EncodedJSValue));
     if (hasDouble(structure()->indexingType())) {
@@ -2361,7 +2363,7 @@ Butterfly* JSObject::growOutOfLineStorage(VM& vm, size_t oldSize, size_t newSize
     // It's important that this function not rely on structure(), for the property
     // capacity, since we might have already mutated the structure in-place.
     
-    return m_butterfly->growPropertyStorage(vm, structure(), oldSize, newSize);
+    return m_butterfly->growPropertyStorage(vm, this, structure(), oldSize, newSize);
 }
 
 bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
index a5a2545..143080d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
- *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
+ *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
@@ -39,7 +39,6 @@
 #include "Structure.h"
 #include "VM.h"
 #include "JSString.h"
-#include "SlotVisitorInlines.h"
 #include "SparseArrayValueMap.h"
 #include <wtf/StdLibExtras.h>
 
@@ -1145,6 +1144,7 @@ inline JSObject::JSObject(VM& vm, Structure* structure, Butterfly* butterfly)
     : JSCell(vm, structure)
     , m_butterfly(butterfly)
 {
+    vm.heap.ascribeOwner(this, butterfly);
 }
 
 inline JSValue JSObject::prototype() const
index afac130..1be012b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *  Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
@@ -28,6 +28,7 @@
 #include "JSFunctionInlines.h"
 #include "JSProxy.h"
 #include "JSString.h"
+#include "SlotVisitorInlines.h"
 #include "StructureInlines.h"
 
 namespace JSC {
index 062650a..cb1da7c 100644 (file)
@@ -46,7 +46,7 @@ RegExpMatchesArray* RegExpMatchesArray::create(ExecState* exec, JSString* input,
 {
     ASSERT(result);
     VM& vm = exec->vm();
-    Butterfly* butterfly = createArrayButterfly(vm, regExp->numSubpatterns() + 1);
+    Butterfly* butterfly = createArrayButterfly(vm, 0, regExp->numSubpatterns() + 1);
     RegExpMatchesArray* array = new (NotNull, allocateCell<RegExpMatchesArray>(vm.heap)) RegExpMatchesArray(vm, butterfly, exec->lexicalGlobalObject(), input, regExp, result);
     array->finishCreation(vm);
     return array;
index a1d1d77..83e36d4 100644 (file)
@@ -109,27 +109,6 @@ inline bool Structure::masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObjec
     return typeInfo().masqueradesAsUndefined() && globalObject() == lexicalGlobalObject;
 }
 
-ALWAYS_INLINE void SlotVisitor::internalAppend(JSCell* cell)
-{
-    ASSERT(!m_isCheckingForDefaultMarkViolation);
-    if (!cell)
-        return;
-#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);
-}
-
 inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind)
 {
     for (Structure* current = this; current; current = current->previousID()) {
index fe07cf5..db4fa22 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 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
@@ -227,18 +227,6 @@ template <typename U, typename V> inline bool operator==(const WriteBarrierBase<
     return lhs.get() == rhs.get();
 }
 
-// SlotVisitor functions
-
-template<typename T> inline void SlotVisitor::append(WriteBarrierBase<T>* slot)
-{
-    internalAppend(*slot->slot());
-}
-
-ALWAYS_INLINE void SlotVisitor::appendValues(WriteBarrierBase<Unknown>* barriers, size_t count)
-{
-    append(barriers->slot(), count);
-}
-
 } // namespace JSC
 
 #endif // WriteBarrier_h
index 1a3870f..85b9a32 100644 (file)
@@ -1,3 +1,18 @@
+2013-05-27  Filip Pizlo  <fpizlo@apple.com>
+
+        It should be possible to record heap operations (both FastMalloc and JSC GC)
+        https://bugs.webkit.org/show_bug.cgi?id=116848
+
+        Reviewed by Mark Hahnenberg.
+
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/DataLog.cpp:
+        (WTF):
+        (WTF::initializeLogFileOnce):
+        * wtf/FastMalloc.cpp:
+        (WTF::TCMalloc_ThreadCache::CreateCacheIfNecessary):
+        * wtf/Platform.h:
+
 2013-05-21  Filip Pizlo  <fpizlo@apple.com>
 
         fourthTier: DFG should be able to run on a separate thread
index d0d5a57..8f21de1 100644 (file)
@@ -56,6 +56,8 @@ static pthread_once_t initializeLogFileOnceKey = PTHREAD_ONCE_INIT;
 
 static FilePrintStream* file;
 
+static uint64_t fileData[(sizeof(FilePrintStream) + 7) / 8];
+
 static void initializeLogFileOnce()
 {
 #if DATA_LOG_TO_FILE
@@ -78,8 +80,11 @@ static void initializeLogFileOnce()
             fprintf(stderr, "Warning: Could not open log file %s for writing.\n", actualFilename);
     }
 #endif // DATA_LOG_TO_FILE
-    if (!file)
-        file = new FilePrintStream(stderr, FilePrintStream::Borrow);
+    if (!file) {
+        // Use placement new; this makes it easier to use dataLog() to debug
+        // fastMalloc.
+        file = new (fileData) FilePrintStream(stderr, FilePrintStream::Borrow);
+    }
     
     setvbuf(file->file(), 0, _IONBF, 0); // Prefer unbuffered output, so that we get a full log upon crash or deadlock.
 }
index ce52aa9..da9a025 100644 (file)
@@ -87,6 +87,7 @@
 #include <pthread.h>
 #endif
 #include <string.h>
+#include <wtf/DataLog.h>
 #include <wtf/StdLibExtras.h>
 
 #if OS(DARWIN)
@@ -4171,12 +4172,22 @@ ALWAYS_INLINE void* malloc(size_t);
 
 void* fastMalloc(size_t size)
 {
-    return malloc<true>(size);
+    void* result = malloc<true>(size);
+#if ENABLE(ALLOCATION_LOGGING)
+    dataLogF("fastMalloc allocating %lu bytes (fastMalloc): %p.\n", size, result);
+#endif
+    return result;
 }
 
 TryMallocReturnValue tryFastMalloc(size_t size)
 {
-    return malloc<false>(size);
+    TryMallocReturnValue result = malloc<false>(size);
+#if ENABLE(ALLOCATION_LOGGING)
+    void* pointer;
+    (void)result.getValue(pointer);
+    dataLogF("fastMalloc allocating %lu bytes (tryFastMalloc): %p.\n", size, pointer);
+#endif
+    return result;
 }
 
 template <bool crashOnFailure>
@@ -4211,6 +4222,10 @@ void* malloc(size_t size) {
 extern "C" 
 #endif
 void free(void* ptr) {
+#if ENABLE(ALLOCATION_LOGGING)
+    dataLogF("fastFree freeing %p.\n", ptr);
+#endif
+    
 #ifndef WTF_CHANGES
   MallocHook::InvokeDeleteHook(ptr);
 #endif
@@ -4240,6 +4255,9 @@ void* fastCalloc(size_t n, size_t elem_size)
 #if ENABLE(WTF_MALLOC_VALIDATION)
     fastMallocValidate(result);
 #endif
+#if ENABLE(ALLOCATION_LOGGING)
+    dataLogF("fastMalloc contiguously allocating %lu * %lu bytes (fastCalloc): %p.\n", n, elem_size, result);
+#endif
     return result;
 }
 
@@ -4249,6 +4267,9 @@ TryMallocReturnValue tryFastCalloc(size_t n, size_t elem_size)
 #if ENABLE(WTF_MALLOC_VALIDATION)
     fastMallocValidate(result);
 #endif
+#if ENABLE(ALLOCATION_LOGGING)
+    dataLogF("fastMalloc contiguously allocating %lu * %lu bytes (tryFastCalloc): %p.\n", n, elem_size, result);
+#endif
     return result;
 }
 
@@ -4310,6 +4331,9 @@ void* fastRealloc(void* old_ptr, size_t new_size)
 #if ENABLE(WTF_MALLOC_VALIDATION)
     fastMallocValidate(result);
 #endif
+#if ENABLE(ALLOCATION_LOGGING)
+    dataLogF("fastMalloc reallocating %lu bytes (fastRealloc): %p -> %p.\n", new_size, old_ptr, result);
+#endif
     return result;
 }
 
@@ -4322,6 +4346,9 @@ TryMallocReturnValue tryFastRealloc(void* old_ptr, size_t new_size)
 #if ENABLE(WTF_MALLOC_VALIDATION)
     fastMallocValidate(result);
 #endif
+#if ENABLE(ALLOCATION_LOGGING)
+    dataLogF("fastMalloc reallocating %lu bytes (tryFastRealloc): %p -> %p.\n", new_size, old_ptr, result);
+#endif
     return result;
 }
 
index 2a5ae2a..8b0f11a 100644 (file)
 #define ENABLE_WRITE_BARRIER_PROFILING 0
 #endif
 
+/* Logs all allocation-related activity that goes through fastMalloc or the
+   JSC GC (both cells and butterflies). Also logs marking. Note that this
+   isn't a completely accurate view of the heap since it doesn't include all
+   butterfly resize operations, doesn't tell you what is going on with weak
+   references (other than to tell you when they're marked), and doesn't
+   track direct mmap() allocations or things like JIT allocation. */
+#if !defined(ENABLE_ALLOCATION_LOGGING)
+#define ENABLE_ALLOCATION_LOGGING 0
+#endif
+
 /* Enable verification that that register allocations are not made within generated control flow.
    Turned on for debug builds. */
 #if !defined(ENABLE_DFG_REGISTER_ALLOCATION_VALIDATION) && ENABLE(DFG_JIT)