1 ////////////////////////////////////////////////////////////////////////////////
3 // Pythonc memory allocator
5 // Copyright 2011 Zach Wegner
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
19 ////////////////////////////////////////////////////////////////////////////////
24 #define BLOCK_SIZE (1 << 14)
25 #define CHUNK_SIZE (1 << 22)
27 typedef unsigned char byte
;
29 uint32_t bitscan64(uint64_t r
) {
30 asm ("bsfq %0, %0" : "=r" (r
) : "0" (r
));
34 template <uint64_t obj_size
>
37 static const uint64_t capacity
= BLOCK_SIZE
- sizeof(void *);
38 static const uint64_t n_objects
= (capacity
* 64 / (obj_size
* 64 + 8)) & ~63;
39 byte data
[obj_size
* n_objects
];
40 arena_block
<obj_size
> *next_block
;
41 uint64_t live_bits
[n_objects
/ 64];
42 byte padding
[capacity
- (obj_size
* n_objects
+ n_objects
/ 8)];
45 assert(sizeof(arena_block
<obj_size
>) == BLOCK_SIZE
);
46 assert(sizeof(this->live_bits
) * 8 == n_objects
);
50 for (uint32_t t
= 0; t
< n_objects
/ 64; t
++)
51 this->live_bits
[t
] = 0;
54 for (uint32_t t
= 0; t
< n_objects
/ 64; t
++) {
55 uint64_t dead
= ~this->live_bits
[t
];
57 uint32_t bit
= bitscan64(dead
);
58 uint32_t idx
= t
* 64 + bit
;
59 this->live_bits
[t
] |= (1ull << bit
);
60 byte
*b
= &this->data
[idx
* obj_size
];
66 bool mark_live(uint32_t idx
) {
67 uint32_t t
= idx
/ 64;
68 uint64_t bit
= 1ull << (idx
& 63);
69 bool already_live
= (this->live_bits
[t
] & bit
) != 0ull;
70 this->live_bits
[t
] |= bit
;
75 // Silly preprocessor stuff for "cleanly" handling multiple block sizes.
76 #define FOR_EACH_OBJ_SIZE(x) x(16) x(24) x(32) x(40) x(56) x(64) x(72)
80 #define DECL_BLOCK(size) arena_block<size> *head_##size;
81 FOR_EACH_OBJ_SIZE(DECL_BLOCK
)
83 byte
*chunk_start
, *chunk_end
;
87 this->get_new_chunk();
88 #define INIT_BLOCK(size) \
89 this->head_##size = (arena_block<size> *)this->new_block(); \
90 this->head_##size->init();
92 FOR_EACH_OBJ_SIZE(INIT_BLOCK
)
96 void get_new_chunk() {
97 this->chunk_start
= new byte
[CHUNK_SIZE
];
98 this->chunk_end
= chunk_start
+ CHUNK_SIZE
;
99 // Align the start of the chunk
100 this->chunk_start
= (byte
*)(((uint64_t)this->chunk_start
+ BLOCK_SIZE
- 1) & ~(BLOCK_SIZE
- 1));
104 if (this->chunk_end
- this->chunk_start
< BLOCK_SIZE
)
105 this->get_new_chunk();
107 void *block
= this->chunk_start
;
108 this->chunk_start
+= BLOCK_SIZE
;
112 void *allocate(uint64_t bytes
) {
114 #define OBJ_CASE(size) \
116 arena_block<size> *block = this->head_##size; \
117 void *p = block->get_obj(); \
119 block = (arena_block<size> *)this->new_block(); \
121 block->next_block = this->head_##size; \
122 this->head_##size = block; \
123 p = block->get_obj(); \
128 FOR_EACH_OBJ_SIZE(OBJ_CASE
)
131 printf("bad obj size %" PRIu64
"\n", bytes
);
137 #define MARK_DEAD(size) \
138 for (arena_block<size> *p = this->head_##size; p; p = p->next_block) \
141 FOR_EACH_OBJ_SIZE(MARK_DEAD
)
144 bool mark_live(void *object
, uint64_t bytes
) {
145 uint32_t idx
= ((uint64_t)object
& (BLOCK_SIZE
- 1)) / bytes
;
146 void *block
= (void *)((uint64_t)object
& ~(BLOCK_SIZE
- 1));
148 #define OBJ_CASE(size) case size: return ((arena_block<size> *)block)->mark_live(idx);
149 FOR_EACH_OBJ_SIZE(OBJ_CASE
)
152 printf("bad obj size %" PRIu64
"\n", bytes
);
160 void *operator new(size_t bytes
, arena
*a
) {
161 return a
->allocate(bytes
);