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