summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/heap/HeapInlines.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/heap/HeapInlines.h')
-rw-r--r--Source/JavaScriptCore/heap/HeapInlines.h358
1 files changed, 358 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/heap/HeapInlines.h b/Source/JavaScriptCore/heap/HeapInlines.h
new file mode 100644
index 000000000..cee723430
--- /dev/null
+++ b/Source/JavaScriptCore/heap/HeapInlines.h
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HeapInlines_h
+#define HeapInlines_h
+
+#include "CopyBarrier.h"
+#include "Heap.h"
+#include "JSCell.h"
+#include "Structure.h"
+#include <type_traits>
+#include <wtf/Assertions.h>
+
+namespace JSC {
+
+inline bool Heap::shouldCollect()
+{
+ if (isDeferred())
+ return false;
+ if (!m_isSafeToCollect)
+ return false;
+ if (m_operationInProgress != NoOperation)
+ return false;
+ if (Options::gcMaxHeapSize())
+ return m_bytesAllocatedThisCycle > Options::gcMaxHeapSize();
+ return m_bytesAllocatedThisCycle > m_maxEdenSize;
+}
+
+inline bool Heap::isBusy()
+{
+ return m_operationInProgress != NoOperation;
+}
+
+inline bool Heap::isCollecting()
+{
+ return m_operationInProgress == FullCollection || m_operationInProgress == EdenCollection;
+}
+
+inline Heap* Heap::heap(const JSCell* cell)
+{
+ return MarkedBlock::blockFor(cell)->heap();
+}
+
+inline Heap* Heap::heap(const JSValue v)
+{
+ if (!v.isCell())
+ return 0;
+ return heap(v.asCell());
+}
+
+inline bool Heap::isLive(const void* cell)
+{
+ return MarkedBlock::blockFor(cell)->isLiveCell(cell);
+}
+
+inline bool Heap::isMarked(const void* cell)
+{
+ return MarkedBlock::blockFor(cell)->isMarked(cell);
+}
+
+inline bool Heap::testAndSetMarked(const void* cell)
+{
+ return MarkedBlock::blockFor(cell)->testAndSetMarked(cell);
+}
+
+inline void Heap::setMarked(const void* cell)
+{
+ MarkedBlock::blockFor(cell)->setMarked(cell);
+}
+
+inline void Heap::writeBarrier(const JSCell* from, JSValue to)
+{
+#if ENABLE(WRITE_BARRIER_PROFILING)
+ WriteBarrierCounters::countWriteBarrier();
+#endif
+ if (!to.isCell())
+ return;
+ writeBarrier(from, to.asCell());
+}
+
+inline void Heap::writeBarrier(const JSCell* from, JSCell* to)
+{
+#if ENABLE(WRITE_BARRIER_PROFILING)
+ WriteBarrierCounters::countWriteBarrier();
+#endif
+ if (!from || from->cellState() != CellState::OldBlack)
+ return;
+ if (!to || to->cellState() != CellState::NewWhite)
+ return;
+ addToRememberedSet(from);
+}
+
+inline void Heap::writeBarrier(const JSCell* from)
+{
+ ASSERT_GC_OBJECT_LOOKS_VALID(const_cast<JSCell*>(from));
+ if (!from || from->cellState() != CellState::OldBlack)
+ return;
+ addToRememberedSet(from);
+}
+
+inline void Heap::reportExtraMemoryAllocated(size_t size)
+{
+ if (size > minExtraMemory)
+ reportExtraMemoryAllocatedSlowCase(size);
+}
+
+inline void Heap::reportExtraMemoryVisited(CellState dataBeforeVisiting, size_t size)
+{
+ // We don't want to double-count the extra memory that was reported in previous collections.
+ if (operationInProgress() == EdenCollection && dataBeforeVisiting == CellState::OldGrey)
+ return;
+
+ size_t* counter = &m_extraMemorySize;
+
+ for (;;) {
+ size_t oldSize = *counter;
+ if (WTF::weakCompareAndSwap(counter, oldSize, oldSize + size))
+ return;
+ }
+}
+
+inline void Heap::deprecatedReportExtraMemory(size_t size)
+{
+ if (size > minExtraMemory)
+ deprecatedReportExtraMemorySlowCase(size);
+}
+
+template<typename Functor> inline void Heap::forEachCodeBlock(Functor& functor)
+{
+ // We don't know the full set of CodeBlocks until compilation has terminated.
+ completeAllDFGPlans();
+
+ return m_codeBlocks.iterate<Functor>(functor);
+}
+
+template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor)
+{
+ for (auto& pair : m_protectedValues)
+ functor(pair.key);
+ m_handleSet.forEachStrongHandle(functor, m_protectedValues);
+
+ return functor.returnValue();
+}
+
+template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell()
+{
+ Functor functor;
+ return forEachProtectedCell(functor);
+}
+
+inline void* Heap::allocateWithDestructor(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.allocateWithDestructor(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);
+}
+
+template<typename ClassType>
+void* Heap::allocateObjectOfType(size_t bytes)
+{
+ // JSCell::classInfo() expects objects allocated with normal destructor to derive from JSDestructibleObject.
+ ASSERT((!ClassType::needsDestruction || (ClassType::StructureFlags & StructureIsImmortal) || std::is_convertible<ClassType, JSDestructibleObject>::value));
+
+ if (ClassType::needsDestruction)
+ return allocateWithDestructor(bytes);
+ return allocateWithoutDestructor(bytes);
+}
+
+template<typename ClassType>
+MarkedSpace::Subspace& Heap::subspaceForObjectOfType()
+{
+ // JSCell::classInfo() expects objects allocated with normal destructor to derive from JSDestructibleObject.
+ ASSERT((!ClassType::needsDestruction || (ClassType::StructureFlags & StructureIsImmortal) || std::is_convertible<ClassType, JSDestructibleObject>::value));
+
+ if (ClassType::needsDestruction)
+ return subspaceForObjectDestructor();
+ return subspaceForObjectWithoutDestructor();
+}
+
+template<typename ClassType>
+MarkedAllocator& Heap::allocatorForObjectOfType(size_t bytes)
+{
+ // JSCell::classInfo() expects objects allocated with normal destructor to derive from JSDestructibleObject.
+ ASSERT((!ClassType::needsDestruction || (ClassType::StructureFlags & StructureIsImmortal) || std::is_convertible<ClassType, JSDestructibleObject>::value));
+
+ if (ClassType::needsDestruction)
+ return allocatorForObjectWithDestructor(bytes);
+ return allocatorForObjectWithoutDestructor(bytes);
+}
+
+inline CheckedBoolean Heap::tryAllocateStorage(JSCell* intendedOwner, size_t bytes, void** 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(JSCell* intendedOwner, void** ptr, size_t oldSize, size_t 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
+}
+
+#if USE(CF)
+template <typename T>
+inline void Heap::releaseSoon(RetainPtr<T>&& object)
+{
+ m_delayedReleaseObjects.append(WTFMove(object));
+}
+#endif
+
+inline void Heap::incrementDeferralDepth()
+{
+ RELEASE_ASSERT(m_deferralDepth < 100); // Sanity check to make sure this doesn't get ridiculous.
+ m_deferralDepth++;
+}
+
+inline void Heap::decrementDeferralDepth()
+{
+ RELEASE_ASSERT(m_deferralDepth >= 1);
+ m_deferralDepth--;
+}
+
+inline bool Heap::collectIfNecessaryOrDefer()
+{
+ if (!shouldCollect())
+ return false;
+
+ collect();
+ return true;
+}
+
+inline void Heap::decrementDeferralDepthAndGCIfNeeded()
+{
+ decrementDeferralDepth();
+ collectIfNecessaryOrDefer();
+}
+
+inline HashSet<MarkedArgumentBuffer*>& Heap::markListSet()
+{
+ if (!m_markListSet)
+ m_markListSet = std::make_unique<HashSet<MarkedArgumentBuffer*>>();
+ return *m_markListSet;
+}
+
+inline void Heap::registerWeakGCMap(void* weakGCMap, std::function<void()> pruningCallback)
+{
+ m_weakGCMaps.add(weakGCMap, WTFMove(pruningCallback));
+}
+
+inline void Heap::unregisterWeakGCMap(void* weakGCMap)
+{
+ m_weakGCMaps.remove(weakGCMap);
+}
+
+inline void Heap::didAllocateBlock(size_t capacity)
+{
+#if ENABLE(RESOURCE_USAGE)
+ m_blockBytesAllocated += capacity;
+#else
+ UNUSED_PARAM(capacity);
+#endif
+}
+
+inline void Heap::didFreeBlock(size_t capacity)
+{
+#if ENABLE(RESOURCE_USAGE)
+ m_blockBytesAllocated -= capacity;
+#else
+ UNUSED_PARAM(capacity);
+#endif
+}
+
+inline bool Heap::isPointerGCObject(TinyBloomFilter filter, MarkedBlockSet& markedBlockSet, void* pointer)
+{
+ MarkedBlock* candidate = MarkedBlock::blockFor(pointer);
+ if (filter.ruleOut(bitwise_cast<Bits>(candidate))) {
+ ASSERT(!candidate || !markedBlockSet.set().contains(candidate));
+ return false;
+ }
+
+ if (!MarkedBlock::isAtomAligned(pointer))
+ return false;
+
+ if (!markedBlockSet.set().contains(candidate))
+ return false;
+
+ if (!candidate->isLiveCell(pointer))
+ return false;
+
+ return true;
+}
+
+inline bool Heap::isValueGCObject(TinyBloomFilter filter, MarkedBlockSet& markedBlockSet, JSValue value)
+{
+ if (!value.isCell())
+ return false;
+ return isPointerGCObject(filter, markedBlockSet, static_cast<void*>(value.asCell()));
+}
+
+} // namespace JSC
+
+#endif // HeapInlines_h