1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). 4 ** Contact: http://www.qt-project.org/legal 5 ** 6 ** This file is part of the Qt Solutions component. 7 ** 8 ** $QT_BEGIN_LICENSE:BSD$ 9 ** You may use this file under the terms of the BSD license as follows: 10 ** 11 ** "Redistribution and use in source and binary forms, with or without 12 ** modification, are permitted provided that the following conditions are 13 ** met: 14 ** * Redistributions of source code must retain the above copyright 15 ** notice, this list of conditions and the following disclaimer. 16 ** * Redistributions in binary form must reproduce the above copyright 17 ** notice, this list of conditions and the following disclaimer in 18 ** the documentation and/or other materials provided with the 19 ** distribution. 20 ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names 21 ** of its contributors may be used to endorse or promote products derived 22 ** from this software without specific prior written permission. 23 ** 24 ** 25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 36 ** 37 ** $QT_END_LICENSE$ 38 ** 39 ****************************************************************************/ 40 41 42 #ifndef QSCRIPTGC_P_H 43 #define QSCRIPTGC_P_H 44 45 // 46 // W A R N I N G 47 // ------------- 48 // 49 // This file is not part of the Qt API. It exists purely as an 50 // implementation detail. This header file may change from version to 51 // version without notice, or even be removed. 52 // 53 // We mean it. 54 // 55 56 #if defined(Q_OS_VXWORKS) && defined(m_free) 57 # undef m_free 58 #endif 59 60 #include <qglobal.h> 61 62 63 #include <QtDebug> 64 #include <new> 65 66 #include "qscriptmemorypool_p.h" 67 68 QT_BEGIN_NAMESPACE 69 70 namespace QScript { 71 72 class GCBlock 73 { 74 public: 75 GCBlock *next; 76 77 union { 78 int generation; 79 uint flags; 80 }; 81 82 public: GCBlock(GCBlock * n)83 inline GCBlock(GCBlock *n): 84 next(n), flags(0) {} 85 data()86 inline void *data() 87 { return reinterpret_cast<char *>(this) + sizeof(GCBlock); } 88 get(void * ptr)89 inline static GCBlock *get(void *ptr) 90 { 91 char *where = reinterpret_cast<char *>(ptr); 92 return reinterpret_cast<GCBlock *>(where - sizeof(GCBlock)); 93 } 94 }; 95 96 template <typename _Tp> 97 class GCAlloc 98 { 99 private: 100 int m_new_allocated_blocks; 101 int m_free_blocks; 102 int m_new_allocated_extra_bytes; 103 GCBlock *m_head; 104 GCBlock *m_current; 105 GCBlock *m_free; 106 bool m_blocked_gc; 107 bool m_force_gc; 108 bool m_sweeping; 109 MemoryPool pool; 110 _Tp trivial; 111 112 public: 113 enum { MaxNumberOfBlocks = 1 << 14 }; 114 enum { MaxNumberOfExtraBytes = 0x800000 }; 115 116 public: GCAlloc()117 inline GCAlloc(): 118 m_new_allocated_blocks(0), 119 m_free_blocks(0), 120 m_new_allocated_extra_bytes(0), 121 m_head(0), 122 m_current(0), 123 m_free(0), 124 m_blocked_gc(false), 125 m_force_gc(false), 126 m_sweeping(false) { 127 trivial.reset(); 128 } 129 ~GCAlloc()130 inline ~GCAlloc() { 131 } 132 destruct()133 inline void destruct() { 134 m_sweeping = true; 135 GCBlock *blk = m_free; 136 137 if (! blk) { 138 blk = m_head; 139 m_head = 0; 140 } 141 142 while (blk) { 143 GCBlock *was = blk; 144 blk = blk->next; 145 146 Q_ASSERT(was->data()); 147 _Tp *data = reinterpret_cast<_Tp*>(was->data()); 148 data->~_Tp(); 149 blk->~GCBlock(); 150 151 if (! blk && m_head) { 152 blk = m_head; 153 m_head = 0; 154 } 155 } 156 m_sweeping = false; 157 } 158 newAllocatedBlocks()159 inline int newAllocatedBlocks() const { return m_new_allocated_blocks; } freeBlocks()160 inline int freeBlocks() const { return m_free_blocks; } 161 operator()162 inline _Tp *operator()(int generation) 163 { 164 GCBlock *previous = m_current; 165 void *where = 0; 166 167 if (! m_free) { 168 Q_ASSERT (m_free_blocks == 0); 169 where = pool.allocate(sizeof(GCBlock) + sizeof(_Tp)); 170 ++m_new_allocated_blocks; 171 (void) new (reinterpret_cast<char*>(where) + sizeof(GCBlock)) _Tp(); 172 } else { 173 --m_free_blocks; 174 where = m_free; 175 m_free = m_free->next; 176 177 if (! m_free) 178 m_force_gc = true; 179 } 180 181 m_current = new (where) GCBlock(0); 182 183 if (! previous) { 184 Q_ASSERT(! m_head); 185 m_head = m_current; 186 } else { 187 previous->next = m_current; 188 } 189 m_current->generation = generation; 190 191 return reinterpret_cast<_Tp*> (m_current->data()); 192 } 193 blocked()194 inline bool blocked() const 195 { 196 return m_blocked_gc; 197 } 198 sweeping()199 inline bool sweeping() const 200 { 201 return m_sweeping; 202 } 203 blockGC(bool block)204 inline bool blockGC(bool block) 205 { 206 bool was = m_blocked_gc; 207 m_blocked_gc = block; 208 return was; 209 } 210 requestGC()211 inline void requestGC() 212 { 213 m_force_gc = true; 214 } 215 adjustBytesAllocated(int bytes)216 inline void adjustBytesAllocated(int bytes) 217 { m_new_allocated_extra_bytes += bytes; } 218 poll()219 inline bool poll() 220 { 221 if (m_blocked_gc || ! m_head) 222 return false; 223 224 else if (m_force_gc) { 225 m_force_gc = false; 226 return true; 227 } 228 229 else if (m_free && ! m_free->next) 230 return true; 231 232 return (m_new_allocated_blocks >= MaxNumberOfBlocks) 233 || ((m_new_allocated_extra_bytes >= MaxNumberOfExtraBytes) 234 && (m_new_allocated_blocks > 0)); 235 } 236 generation(_Tp * ptr)237 inline int generation(_Tp *ptr) const 238 { return GCBlock::get(ptr)->generation; } 239 head()240 inline GCBlock *head() const 241 { return m_head; } 242 sweep(int generation)243 void sweep(int generation) 244 { 245 m_sweeping = true; 246 GCBlock *blk = m_head; 247 m_current = 0; 248 249 m_new_allocated_blocks = 0; 250 m_new_allocated_extra_bytes = 0; 251 252 while (blk != 0) { 253 if (blk->generation != generation) { 254 if (m_current) 255 m_current->next = blk->next; 256 257 GCBlock *tmp = blk; 258 blk = blk->next; // advance the pointer 259 260 tmp->next = m_free; // prepend the node to the free list... 261 m_free = tmp; 262 ++m_free_blocks; 263 264 if (m_free == m_head) 265 m_head = blk; 266 267 _Tp *data = reinterpret_cast<_Tp *>(tmp->data()); 268 data->finalize(); 269 tmp->~GCBlock(); 270 } else { 271 m_current = blk; 272 blk = blk->next; 273 } 274 } 275 276 if (! m_current) 277 m_head = m_current; 278 m_sweeping = false; 279 } 280 281 class const_iterator 282 { 283 public: 284 typedef _Tp value_type; 285 typedef const _Tp *pointer; 286 typedef const _Tp &reference; const_iterator()287 inline const_iterator() : i(0) { } const_iterator(GCBlock * block)288 inline const_iterator(GCBlock *block) : i(block) { } const_iterator(const const_iterator & o)289 inline const_iterator(const const_iterator &o) 290 { i = reinterpret_cast<const const_iterator &>(o).i; } 291 data()292 inline const _Tp *data() const { return reinterpret_cast<_Tp*>(i->data()); } value()293 inline const _Tp &value() const { return *reinterpret_cast<_Tp*>(i->data()); } 294 inline const _Tp &operator*() const { return *reinterpret_cast<_Tp*>(i->data()); } 295 inline const _Tp *operator->() const { return reinterpret_cast<_Tp*>(i->data()); } 296 inline bool operator==(const const_iterator &o) const { return i == o.i; } 297 inline bool operator!=(const const_iterator &o) const { return i != o.i; } 298 299 inline const_iterator &operator++() { 300 i = i->next; 301 return *this; 302 } 303 private: 304 GCBlock *i; 305 }; 306 friend class const_iterator; 307 constBegin()308 inline const_iterator constBegin() const { return const_iterator(m_head); } constEnd()309 inline const_iterator constEnd() const { return const_iterator(0); } 310 311 private: 312 Q_DISABLE_COPY(GCAlloc) 313 }; 314 315 } // namespace QScript 316 317 QT_END_NAMESPACE 318 319 #endif // QSCRIPT_GC_H 320