1/* 2 * Copyright (C) 2011 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#ifndef CopiedAllocator_h 27#define CopiedAllocator_h 28 29#include "CopiedBlock.h" 30#include <wtf/CheckedBoolean.h> 31#include <wtf/DataLog.h> 32 33namespace JSC { 34 35class CopiedAllocator { 36public: 37 CopiedAllocator(); 38 39 bool fastPathShouldSucceed(size_t bytes) const; 40 CheckedBoolean tryAllocate(size_t bytes, void** outPtr); 41 CheckedBoolean tryAllocateDuringCopying(size_t bytes, void** outPtr); 42 CheckedBoolean tryReallocate(void *oldPtr, size_t oldBytes, size_t newBytes); 43 void* forceAllocate(size_t bytes); 44 CopiedBlock* resetCurrentBlock(); 45 void setCurrentBlock(CopiedBlock*); 46 size_t currentCapacity(); 47 48 bool isValid() { return !!m_currentBlock; } 49 50 CopiedBlock* currentBlock() { return m_currentBlock; } 51 52 // Yes, these are public. No, that doesn't mean you can play with them. 53 // If I had made them private then I'd have to list off all of the JIT 54 // classes and functions that are entitled to modify these directly, and 55 // that would have been gross. 56 size_t m_currentRemaining; 57 char* m_currentPayloadEnd; 58 CopiedBlock* m_currentBlock; 59}; 60 61inline CopiedAllocator::CopiedAllocator() 62 : m_currentRemaining(0) 63 , m_currentPayloadEnd(0) 64 , m_currentBlock(0) 65{ 66} 67 68inline bool CopiedAllocator::fastPathShouldSucceed(size_t bytes) const 69{ 70 ASSERT(is8ByteAligned(reinterpret_cast<void*>(bytes))); 71 72 return bytes <= m_currentRemaining; 73} 74 75inline CheckedBoolean CopiedAllocator::tryAllocate(size_t bytes, void** outPtr) 76{ 77 ASSERT(is8ByteAligned(reinterpret_cast<void*>(bytes))); 78 79 // This code is written in a gratuitously low-level manner, in order to 80 // serve as a kind of template for what the JIT would do. Note that the 81 // way it's written it ought to only require one register, which doubles 82 // as the result, provided that the compiler does a minimal amount of 83 // control flow simplification and the bytes argument is a constant. 84 85 size_t currentRemaining = m_currentRemaining; 86 if (bytes > currentRemaining) 87 return false; 88 currentRemaining -= bytes; 89 m_currentRemaining = currentRemaining; 90 *outPtr = m_currentPayloadEnd - currentRemaining - bytes; 91 92 ASSERT(is8ByteAligned(*outPtr)); 93 94 return true; 95} 96 97inline CheckedBoolean CopiedAllocator::tryAllocateDuringCopying(size_t bytes, void** outPtr) 98{ 99 if (!tryAllocate(bytes, outPtr)) 100 return false; 101 m_currentBlock->reportLiveBytesDuringCopying(bytes); 102 return true; 103} 104 105inline CheckedBoolean CopiedAllocator::tryReallocate( 106 void* oldPtr, size_t oldBytes, size_t newBytes) 107{ 108 ASSERT(is8ByteAligned(oldPtr)); 109 ASSERT(is8ByteAligned(reinterpret_cast<void*>(oldBytes))); 110 ASSERT(is8ByteAligned(reinterpret_cast<void*>(newBytes))); 111 112 ASSERT(newBytes > oldBytes); 113 114 size_t additionalBytes = newBytes - oldBytes; 115 116 size_t currentRemaining = m_currentRemaining; 117 if (m_currentPayloadEnd - currentRemaining - oldBytes != static_cast<char*>(oldPtr)) 118 return false; 119 120 if (additionalBytes > currentRemaining) 121 return false; 122 123 m_currentRemaining = currentRemaining - additionalBytes; 124 125 return true; 126} 127 128inline void* CopiedAllocator::forceAllocate(size_t bytes) 129{ 130 void* result = 0; // Needed because compilers don't realize this will always be assigned. 131 CheckedBoolean didSucceed = tryAllocate(bytes, &result); 132 ASSERT(didSucceed); 133 return result; 134} 135 136inline CopiedBlock* CopiedAllocator::resetCurrentBlock() 137{ 138 CopiedBlock* result = m_currentBlock; 139 if (result) { 140 result->m_remaining = m_currentRemaining; 141 m_currentBlock = 0; 142 m_currentRemaining = 0; 143 m_currentPayloadEnd = 0; 144 } 145 return result; 146} 147 148inline void CopiedAllocator::setCurrentBlock(CopiedBlock* newBlock) 149{ 150 ASSERT(!m_currentBlock); 151 m_currentBlock = newBlock; 152 ASSERT(newBlock); 153 m_currentRemaining = newBlock->m_remaining; 154 m_currentPayloadEnd = newBlock->payloadEnd(); 155} 156 157inline size_t CopiedAllocator::currentCapacity() 158{ 159 if (!m_currentBlock) 160 return 0; 161 return m_currentBlock->capacity(); 162} 163 164} // namespace JSC 165 166#endif 167