]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - heap/CopiedAllocator.h
JavaScriptCore-7600.1.4.15.12.tar.gz
[apple/javascriptcore.git] / heap / CopiedAllocator.h
index 7455ec816c62749c782f799482349bb2592ccee0..3dfc9a7fe471780391b651e2ef8bef38f15835a0 100644 (file)
 #define CopiedAllocator_h
 
 #include "CopiedBlock.h"
+#include <wtf/CheckedBoolean.h>
+#include <wtf/DataLog.h>
 
 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<void*>(bytes)));
-    ASSERT(fitsInCurrentBlock(bytes));
-    void* ptr = static_cast<void*>(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<char*>(m_currentBlock) + HeapBlock::s_blockSize && m_currentOffset + bytes > m_currentOffset;
+    ASSERT(is8ByteAligned(reinterpret_cast<void*>(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<void*>(oldBytes)));
+    ASSERT(is8ByteAligned(reinterpret_cast<void*>(newBytes)));
+    
+    ASSERT(newBytes > oldBytes);
+    
+    size_t additionalBytes = newBytes - oldBytes;
+    
+    size_t currentRemaining = m_currentRemaining;
+    if (m_currentPayloadEnd - currentRemaining - oldBytes != static_cast<char*>(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<char*>(ptr) + size == m_currentOffset && ptr > m_currentBlock && ptr < reinterpret_cast<char*>(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<void*>(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<void*>(m_currentOffset);
+    ASSERT(!m_currentBlock);
     m_currentBlock = newBlock;
-    m_currentOffset = static_cast<char*>(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();
 }