Commit a03796ac authored by oliver@apple.com's avatar oliver@apple.com

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
parent 37172f80
......@@ -31,12 +31,12 @@
#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:
......
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
......
......@@ -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)
......
......@@ -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()
......
......@@ -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()
......
......@@ -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()
......
/*
* 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();
......
/*
* 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)
......
......@@ -137,7 +137,7 @@ public:
template<typename T> inline void SlotVisitor::append(JITWriteBarrier<T>* slot)
{
internalAppend(slot->get());
internalAppend(0, slot->get());
}
}
......
/*
* 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
......@@ -34,7 +34,11 @@
// 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
......
......@@ -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);
};
......
......@@ -35,27 +35,30 @@
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);
}
......
......@@ -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)