1/* 2 * Copyright (c) 2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_APACHE_LICENSE_HEADER_START@ 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * @APPLE_APACHE_LICENSE_HEADER_END@ 19 */ 20/* 21 AutoLarge.h 22 Large Block Support 23 Copyright (c) 2004-2011 Apple Inc. All rights reserved. 24 */ 25 26#pragma once 27#ifndef __AUTO_LARGE__ 28#define __AUTO_LARGE__ 29 30#include "Definitions.h" 31#include "Statistics.h" 32#include "WriteBarrier.h" 33#include "auto_zone.h" 34 35namespace Auto { 36 37 // 38 // Forward declarations 39 // 40 41 class Zone; 42 43 //----- Large -----// 44 45 // 46 // Manages information associated with a large block. 47 // 48 49 class Large { 50 51 private: 52 enum { 53 initial_age = 5 54 }; 55 56 Large *_prev; // previous large block or NULL if head of list 57 Large *_next; // next large block or NULL if tail of list 58 Zone *_zone; // the zone containing the large 59 usword_t _vm_size; // size of the vm allocation 60 usword_t _size; // size of the requested allocation 61 usword_t _layout; // organization of block 62 usword_t _refcount; // large block reference count 63 usword_t _age; // block age 64 bool _is_pending; // needs scanning flag 65 bool _is_marked; // has been visited flag 66 bool _is_garbage; 67 uint32_t _checking_count; // collection checking - count of survived collections + 1 (0 implies unchecked) 68 WriteBarrier _write_barrier; // write barrier accessor object. 69 70 Large(Zone *zone, usword_t vm_size, usword_t size, usword_t layout, usword_t refcount, usword_t age, const WriteBarrier &wb); 71 72 public: 73 74 // 75 // quantum_index 76 // 77 // Returns a memory index for an arbitrary pointer. 78 // 79#if UseArena 80 // XXX not sure if the compiler makes the mask a no-op on 32-bit so go ahead and leave old one 81 // in place until 64-bit tuning occurs 82 // Note that the mask(arena_log2 - large_log2) is defined to work on 32-bit without needing a long long 83 // computation. 84 static inline const usword_t quantum_index(void *address) { return (((usword_t)address >> allocate_quantum_large_log2) & mask(allocate_quantum_large_max_log2)); } 85#else 86 static inline const usword_t quantum_index(void *address) { return ((usword_t)address >> allocate_quantum_large_log2); } 87#endif 88 89 90 // 91 // quantum_count 92 // 93 // Returns a number of memory quantum for a given size. 94 // 95 static inline const usword_t quantum_count(const size_t size) { return partition2(size, allocate_quantum_large_log2); } 96 97 98 // 99 // quantum_large 100 // 101 // Returns the Large of the specified large quantum. 102 // 103 static inline Large *quantum_large(const usword_t q, void*arena) { return (Large *)((usword_t)arena+(q << allocate_quantum_large_log2)); } 104 105 106 // 107 // side_data_size 108 // 109 // Return the size of the block header and guarantee small quantum alignment. 110 // 111 static inline usword_t side_data_size() { return align2(sizeof(Large), allocate_quantum_small_log2); } 112 113 114 // 115 // address 116 // 117 // Return the address of the allocation 118 // 119 inline void *address() { return displace(this, side_data_size()); } 120 121 122 // 123 // is_start 124 // 125 // Returns true if the address is the start of a block. 126 // 127 static inline bool is_start(void *address) { 128 return (((uintptr_t)address) & mask(allocate_quantum_large_log2)) == side_data_size(); 129 } 130 131 132 // 133 // large 134 // 135 // Return the address of the large side data. 136 // 137 static inline Large *large(void *address) { return (Large *)displace(address, -side_data_size()); } 138 139 140 // 141 // allocate 142 // 143 // Allocate memory used for the large block. 144 // 145 static Large *allocate(Zone *zone, const usword_t size, usword_t layout, bool refcount_is_one); 146 147 148 // 149 // deallocate 150 // 151 // Release memory used by the large block. 152 // 153 void deallocate(Zone *zone); 154 155 156 // 157 // Accessors 158 // 159 inline Large *prev() const { return _prev; } 160 inline Large *next() const { return _next; } 161 inline Zone *zone() const { return _zone; } 162 inline usword_t vm_size() const { return _vm_size; } 163 inline void set_prev(Large *prev) { _prev = prev; } 164 inline void set_next(Large *next) { _next = next; } 165 inline Range range() { return Range(address(), size()); } 166 inline void mark_garbage() { _is_garbage = true; } 167 inline bool is_garbage() const { return _is_garbage; } 168 169 inline uint32_t collection_checking_count() const { return _checking_count; } 170 inline void set_collection_checking_count(uint32_t count) { _checking_count = count; } 171 172 // 173 // Side data accessors 174 // 175 inline usword_t size() const { return _size; } 176 177 inline bool is_new() const { return _age != 0; } 178 inline bool is_newest() const { return _age == initial_age; } 179 180 inline usword_t age() const { return _age; } 181 inline void set_age(usword_t a) { _age = a; } 182 183 inline void mature() { _age--; } 184 185 inline bool is_pending() const { return _is_pending; } 186 187 inline bool is_marked() const { return _is_marked; } 188 189 inline usword_t layout() const { return _layout; } 190 191 inline bool is_scanned() const { return ::is_scanned(_layout); } 192 193 inline bool is_object() const { return ::is_object(_layout); } 194 195 inline usword_t refcount() const { return _refcount; } 196 197 inline void set_pending() { _is_pending = true; } 198 199 inline void clear_pending() { _is_pending = false; } 200 201 inline void set_mark() { _is_marked = true; } 202 203 inline void clear_mark() { _is_marked = false; } 204 205 inline bool test_and_set_mark() { 206 bool old = _is_marked; 207 if (!old) _is_marked = true; 208 return old; 209 } 210 211 inline bool test_clear_mark() { 212 bool old = _is_marked; 213 if (old) _is_marked = false; 214 return old; 215 } 216 217 inline void set_refcount(usword_t refcount) { _refcount = refcount; } 218 219 inline void set_layout(usword_t layout) { _layout = layout; } 220 221 // List Operations 222 223 // 224 // add 225 // 226 // Puts this Large block on the front of the specified list. 227 // 228 inline void add(Large *&large_list) { 229 _prev = NULL; 230 _next = large_list; 231 if (large_list) large_list->set_prev(this); 232 large_list = this; 233 } 234 235 // 236 // remove 237 // 238 // Removes this Large block from the specified list. 239 // 240 inline void remove(Large *&large_list) { 241 if (large_list == this) large_list = _next; 242 if (_prev) _prev->set_next(_next); 243 if (_next) _next->set_prev(_prev); 244 _prev = _next = NULL; 245 } 246 247 248 // 249 // write_barrier 250 // 251 // Returns accessor for this large block's write barrier. 252 // 253 inline WriteBarrier& write_barrier() { 254 return _write_barrier; 255 } 256 }; 257 258}; 259 260 261#endif // __AUTO_LARGE__ 262