]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-zalloc.h
objc4-781.tar.gz
[apple/objc4.git] / runtime / objc-zalloc.h
1 /*
2 * Copyright (c) 2019 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /**
25 * @file objc-zalloc.h
26 *
27 * "zone allocator" for objc.
28 *
29 * Provides packed allocation for data structures the runtime
30 * almost never frees.
31 */
32
33 #ifndef _OBJC_ZALLOC_H
34 #define _OBJC_ZALLOC_H
35
36 #include <cstdint>
37 #include <atomic>
38 #include <cstdlib>
39
40 namespace objc {
41
42 // Darwin malloc always aligns to 16 bytes
43 #define MALLOC_ALIGNMENT 16
44
45 class AtomicQueue {
46 #if __LP64__
47 using pair_t = __int128_t;
48 #else
49 using pair_t = uint64_t;
50 #endif
51 static constexpr auto relaxed = std::memory_order_relaxed;
52 static constexpr auto release = std::memory_order_release;
53
54 struct Entry {
55 struct Entry *next;
56 };
57
58 union {
59 struct {
60 Entry *head;
61 unsigned long gen;
62 };
63 std::atomic<pair_t> atomic_pair;
64 pair_t pair;
65 };
66
67 public:
68 void *pop();
69 void push_list(void *_head, void *_tail);
70 inline void push(void *head)
71 {
72 push_list(head, head);
73 }
74 };
75
76 template<class T, bool useMalloc>
77 class Zone {
78 };
79
80 template<class T>
81 class Zone<T, false> {
82 struct Element {
83 Element *next;
84 char buf[sizeof(T) - sizeof(void *)];
85 } __attribute__((packed));
86
87 static AtomicQueue _freelist;
88 static T *alloc_slow();
89
90 public:
91 static T *alloc();
92 static void free(T *);
93 };
94
95 template<class T>
96 class Zone<T, true> {
97 public:
98 static inline T *alloc() {
99 return reinterpret_cast<T *>(::calloc(sizeof(T), 1));
100 }
101 static inline void free(T *ptr) {
102 ::free(ptr);
103 }
104 };
105
106 /*
107 * This allocator returns always zeroed memory,
108 * and the template needs to be instantiated in objc-zalloc.mm
109 */
110
111 template<class T>
112 T *zalloc()
113 {
114 return Zone<T, sizeof(T) % MALLOC_ALIGNMENT == 0>::alloc();
115 }
116
117 template<class T>
118 void zfree(T *e)
119 {
120 Zone<T, sizeof(T) % MALLOC_ALIGNMENT == 0>::free(e);
121 }
122
123 };
124
125 #endif