2 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #ifndef CopiedAllocator_h
27 #define CopiedAllocator_h
29 #include "CopiedBlock.h"
30 #include <wtf/CheckedBoolean.h>
31 #include <wtf/DataLog.h>
35 class CopiedAllocator
{
39 bool fastPathShouldSucceed(size_t bytes
) const;
40 CheckedBoolean
tryAllocate(size_t bytes
, void** outPtr
);
41 CheckedBoolean
tryReallocate(void *oldPtr
, size_t oldBytes
, size_t newBytes
);
42 void* forceAllocate(size_t bytes
);
43 CopiedBlock
* resetCurrentBlock();
44 void setCurrentBlock(CopiedBlock
*);
45 size_t currentCapacity();
47 bool isValid() { return !!m_currentBlock
; }
49 CopiedBlock
* currentBlock() { return m_currentBlock
; }
51 // Yes, these are public. No, that doesn't mean you can play with them.
52 // If I had made them private then I'd have to list off all of the JIT
53 // classes and functions that are entitled to modify these directly, and
54 // that would have been gross.
55 size_t m_currentRemaining
;
56 char* m_currentPayloadEnd
;
57 CopiedBlock
* m_currentBlock
;
60 inline CopiedAllocator::CopiedAllocator()
61 : m_currentRemaining(0)
62 , m_currentPayloadEnd(0)
67 inline bool CopiedAllocator::fastPathShouldSucceed(size_t bytes
) const
69 ASSERT(is8ByteAligned(reinterpret_cast<void*>(bytes
)));
71 return bytes
<= m_currentRemaining
;
74 inline CheckedBoolean
CopiedAllocator::tryAllocate(size_t bytes
, void** outPtr
)
76 ASSERT(is8ByteAligned(reinterpret_cast<void*>(bytes
)));
78 // This code is written in a gratuitously low-level manner, in order to
79 // serve as a kind of template for what the JIT would do. Note that the
80 // way it's written it ought to only require one register, which doubles
81 // as the result, provided that the compiler does a minimal amount of
82 // control flow simplification and the bytes argument is a constant.
84 size_t currentRemaining
= m_currentRemaining
;
85 if (bytes
> currentRemaining
)
87 currentRemaining
-= bytes
;
88 m_currentRemaining
= currentRemaining
;
89 *outPtr
= m_currentPayloadEnd
- currentRemaining
- bytes
;
91 ASSERT(is8ByteAligned(*outPtr
));
96 inline CheckedBoolean
CopiedAllocator::tryReallocate(
97 void* oldPtr
, size_t oldBytes
, size_t newBytes
)
99 ASSERT(is8ByteAligned(oldPtr
));
100 ASSERT(is8ByteAligned(reinterpret_cast<void*>(oldBytes
)));
101 ASSERT(is8ByteAligned(reinterpret_cast<void*>(newBytes
)));
103 ASSERT(newBytes
> oldBytes
);
105 size_t additionalBytes
= newBytes
- oldBytes
;
107 size_t currentRemaining
= m_currentRemaining
;
108 if (m_currentPayloadEnd
- currentRemaining
- oldBytes
!= static_cast<char*>(oldPtr
))
111 if (additionalBytes
> currentRemaining
)
114 m_currentRemaining
= currentRemaining
- additionalBytes
;
119 inline void* CopiedAllocator::forceAllocate(size_t bytes
)
121 void* result
= 0; // Needed because compilers don't realize this will always be assigned.
122 CheckedBoolean didSucceed
= tryAllocate(bytes
, &result
);
127 inline CopiedBlock
* CopiedAllocator::resetCurrentBlock()
129 CopiedBlock
* result
= m_currentBlock
;
131 result
->m_remaining
= m_currentRemaining
;
133 m_currentRemaining
= 0;
134 m_currentPayloadEnd
= 0;
139 inline void CopiedAllocator::setCurrentBlock(CopiedBlock
* newBlock
)
141 ASSERT(!m_currentBlock
);
142 m_currentBlock
= newBlock
;
144 m_currentRemaining
= newBlock
->m_remaining
;
145 m_currentPayloadEnd
= newBlock
->payloadEnd();
148 inline size_t CopiedAllocator::currentCapacity()
152 return m_currentBlock
->capacity();