X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174..refs/heads/master:/heap/CopiedAllocator.h diff --git a/heap/CopiedAllocator.h b/heap/CopiedAllocator.h index 7455ec8..3dfc9a7 100644 --- a/heap/CopiedAllocator.h +++ b/heap/CopiedAllocator.h @@ -27,72 +27,137 @@ #define CopiedAllocator_h #include "CopiedBlock.h" +#include +#include namespace JSC { class CopiedAllocator { - friend class JIT; public: CopiedAllocator(); - void* allocate(size_t); - bool fitsInCurrentBlock(size_t); - bool wasLastAllocation(void*, size_t); - void startedCopying(); - void resetCurrentBlock(CopiedBlock*); + + bool fastPathShouldSucceed(size_t bytes) const; + CheckedBoolean tryAllocate(size_t bytes, void** outPtr); + CheckedBoolean tryAllocateDuringCopying(size_t bytes, void** outPtr); + CheckedBoolean tryReallocate(void *oldPtr, size_t oldBytes, size_t newBytes); + void* forceAllocate(size_t bytes); + CopiedBlock* resetCurrentBlock(); + void setCurrentBlock(CopiedBlock*); size_t currentCapacity(); + + bool isValid() { return !!m_currentBlock; } -private: CopiedBlock* currentBlock() { return m_currentBlock; } - char* m_currentOffset; + // Yes, these are public. No, that doesn't mean you can play with them. + // If I had made them private then I'd have to list off all of the JIT + // classes and functions that are entitled to modify these directly, and + // that would have been gross. + size_t m_currentRemaining; + char* m_currentPayloadEnd; CopiedBlock* m_currentBlock; }; inline CopiedAllocator::CopiedAllocator() - : m_currentOffset(0) + : m_currentRemaining(0) + , m_currentPayloadEnd(0) , m_currentBlock(0) { } -inline void* CopiedAllocator::allocate(size_t bytes) +inline bool CopiedAllocator::fastPathShouldSucceed(size_t bytes) const { - ASSERT(m_currentOffset); ASSERT(is8ByteAligned(reinterpret_cast(bytes))); - ASSERT(fitsInCurrentBlock(bytes)); - void* ptr = static_cast(m_currentOffset); - m_currentOffset += bytes; - ASSERT(is8ByteAligned(ptr)); - return ptr; + + return bytes <= m_currentRemaining; } -inline bool CopiedAllocator::fitsInCurrentBlock(size_t bytes) +inline CheckedBoolean CopiedAllocator::tryAllocate(size_t bytes, void** outPtr) { - return m_currentOffset + bytes < reinterpret_cast(m_currentBlock) + HeapBlock::s_blockSize && m_currentOffset + bytes > m_currentOffset; + ASSERT(is8ByteAligned(reinterpret_cast(bytes))); + + // This code is written in a gratuitously low-level manner, in order to + // serve as a kind of template for what the JIT would do. Note that the + // way it's written it ought to only require one register, which doubles + // as the result, provided that the compiler does a minimal amount of + // control flow simplification and the bytes argument is a constant. + + size_t currentRemaining = m_currentRemaining; + if (bytes > currentRemaining) + return false; + currentRemaining -= bytes; + m_currentRemaining = currentRemaining; + *outPtr = m_currentPayloadEnd - currentRemaining - bytes; + + ASSERT(is8ByteAligned(*outPtr)); + + return true; +} + +inline CheckedBoolean CopiedAllocator::tryAllocateDuringCopying(size_t bytes, void** outPtr) +{ + if (!tryAllocate(bytes, outPtr)) + return false; + m_currentBlock->reportLiveBytesDuringCopying(bytes); + return true; +} + +inline CheckedBoolean CopiedAllocator::tryReallocate( + void* oldPtr, size_t oldBytes, size_t newBytes) +{ + ASSERT(is8ByteAligned(oldPtr)); + ASSERT(is8ByteAligned(reinterpret_cast(oldBytes))); + ASSERT(is8ByteAligned(reinterpret_cast(newBytes))); + + ASSERT(newBytes > oldBytes); + + size_t additionalBytes = newBytes - oldBytes; + + size_t currentRemaining = m_currentRemaining; + if (m_currentPayloadEnd - currentRemaining - oldBytes != static_cast(oldPtr)) + return false; + + if (additionalBytes > currentRemaining) + return false; + + m_currentRemaining = currentRemaining - additionalBytes; + + return true; } -inline bool CopiedAllocator::wasLastAllocation(void* ptr, size_t size) +inline void* CopiedAllocator::forceAllocate(size_t bytes) { - return static_cast(ptr) + size == m_currentOffset && ptr > m_currentBlock && ptr < reinterpret_cast(m_currentBlock) + HeapBlock::s_blockSize; + void* result = 0; // Needed because compilers don't realize this will always be assigned. + CheckedBoolean didSucceed = tryAllocate(bytes, &result); + ASSERT(didSucceed); + return result; } -inline void CopiedAllocator::startedCopying() +inline CopiedBlock* CopiedAllocator::resetCurrentBlock() { - if (m_currentBlock) - m_currentBlock->m_offset = static_cast(m_currentOffset); - m_currentOffset = 0; - m_currentBlock = 0; + CopiedBlock* result = m_currentBlock; + if (result) { + result->m_remaining = m_currentRemaining; + m_currentBlock = 0; + m_currentRemaining = 0; + m_currentPayloadEnd = 0; + } + return result; } -inline void CopiedAllocator::resetCurrentBlock(CopiedBlock* newBlock) +inline void CopiedAllocator::setCurrentBlock(CopiedBlock* newBlock) { - if (m_currentBlock) - m_currentBlock->m_offset = static_cast(m_currentOffset); + ASSERT(!m_currentBlock); m_currentBlock = newBlock; - m_currentOffset = static_cast(newBlock->m_offset); + ASSERT(newBlock); + m_currentRemaining = newBlock->m_remaining; + m_currentPayloadEnd = newBlock->payloadEnd(); } inline size_t CopiedAllocator::currentCapacity() { + if (!m_currentBlock) + return 0; return m_currentBlock->capacity(); }