]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-opt.mm
objc4-647.tar.gz
[apple/objc4.git] / runtime / objc-opt.mm
1 /*
2 * Copyright (c) 2012 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 objc-opt.mm
26 Management of optimizations in the dyld shared cache
27 */
28
29 #include "objc-private.h"
30
31
32 #if !SUPPORT_PREOPT
33 // Preoptimization not supported on this platform.
34
35 struct objc_selopt_t;
36
37 bool isPreoptimized(void)
38 {
39 return false;
40 }
41
42 objc_selopt_t *preoptimizedSelectors(void)
43 {
44 return nil;
45 }
46
47 Class getPreoptimizedClass(const char *name)
48 {
49 return nil;
50 }
51
52 Class* copyPreoptimizedClasses(const char *name, int *outCount)
53 {
54 *outCount = 0;
55 return nil;
56 }
57
58 header_info *preoptimizedHinfoForHeader(const headerType *mhdr)
59 {
60 return nil;
61 }
62
63 void preopt_init(void)
64 {
65 disableSharedCacheOptimizations();
66
67 if (PrintPreopt) {
68 _objc_inform("PREOPTIMIZATION: is DISABLED "
69 "(not supported on ths platform)");
70 }
71 }
72
73
74 // !SUPPORT_PREOPT
75 #else
76 // SUPPORT_PREOPT
77
78 #include <objc-shared-cache.h>
79
80 using objc_opt::objc_clsopt_t;
81 using objc_opt::objc_headeropt_t;
82 using objc_opt::objc_opt_t;
83
84 __BEGIN_DECLS
85
86 // preopt: the actual opt used at runtime (nil or &_objc_opt_data)
87 // _objc_opt_data: opt data possibly written by dyld
88 // opt is initialized to ~0 to detect incorrect use before preopt_init()
89
90 static const objc_opt_t *opt = (objc_opt_t *)~0;
91 static bool preoptimized;
92
93 extern const objc_opt_t _objc_opt_data; // in __TEXT, __objc_opt_ro
94
95 bool isPreoptimized(void)
96 {
97 return preoptimized;
98 }
99
100 objc_selopt_t *preoptimizedSelectors(void)
101 {
102 return opt ? opt->selopt() : nil;
103 }
104
105 Class getPreoptimizedClass(const char *name)
106 {
107 objc_clsopt_t *classes = opt ? opt->clsopt() : nil;
108 if (!classes) return nil;
109
110 void *cls;
111 void *hi;
112 uint32_t count = classes->getClassAndHeader(name, cls, hi);
113 if (count == 1 && ((header_info *)hi)->loaded) {
114 // exactly one matching class, and its image is loaded
115 return (Class)cls;
116 }
117 else if (count > 1) {
118 // more than one matching class - find one that is loaded
119 void *clslist[count];
120 void *hilist[count];
121 classes->getClassesAndHeaders(name, clslist, hilist);
122 for (uint32_t i = 0; i < count; i++) {
123 if (((header_info *)hilist[i])->loaded) {
124 return (Class)clslist[i];
125 }
126 }
127 }
128
129 // no match that is loaded
130 return nil;
131 }
132
133
134 Class* copyPreoptimizedClasses(const char *name, int *outCount)
135 {
136 *outCount = 0;
137
138 objc_clsopt_t *classes = opt ? opt->clsopt() : nil;
139 if (!classes) return nil;
140
141 void *cls;
142 void *hi;
143 uint32_t count = classes->getClassAndHeader(name, cls, hi);
144 if (count == 0) return nil;
145
146 Class *result = (Class *)_calloc_internal(count, sizeof(Class));
147 if (count == 1 && ((header_info *)hi)->loaded) {
148 // exactly one matching class, and its image is loaded
149 result[(*outCount)++] = (Class)cls;
150 return result;
151 }
152 else if (count > 1) {
153 // more than one matching class - find those that are loaded
154 void *clslist[count];
155 void *hilist[count];
156 classes->getClassesAndHeaders(name, clslist, hilist);
157 for (uint32_t i = 0; i < count; i++) {
158 if (((header_info *)hilist[i])->loaded) {
159 result[(*outCount)++] = (Class)clslist[i];
160 }
161 }
162
163 if (*outCount == 0) {
164 // found multiple classes with that name, but none are loaded
165 free(result);
166 result = nil;
167 }
168 return result;
169 }
170
171 // no match that is loaded
172 return nil;
173 }
174
175 namespace objc_opt {
176 struct objc_headeropt_t {
177 uint32_t count;
178 uint32_t entsize;
179 header_info headers[0]; // sorted by mhdr address
180
181 header_info *get(const headerType *mhdr)
182 {
183 assert(entsize == sizeof(header_info));
184
185 int32_t start = 0;
186 int32_t end = count;
187 while (start <= end) {
188 int32_t i = (start+end)/2;
189 header_info *hi = headers+i;
190 if (mhdr == hi->mhdr) return hi;
191 else if (mhdr < hi->mhdr) end = i-1;
192 else start = i+1;
193 }
194
195 #if !NDEBUG
196 for (uint32_t i = 0; i < count; i++) {
197 header_info *hi = headers+i;
198 if (mhdr == hi->mhdr) {
199 _objc_fatal("failed to find header %p (%d/%d)",
200 mhdr, i, count);
201 }
202 }
203 #endif
204
205 return nil;
206 }
207 };
208 };
209
210
211 header_info *preoptimizedHinfoForHeader(const headerType *mhdr)
212 {
213 objc_headeropt_t *hinfos = opt ? opt->headeropt() : nil;
214 if (hinfos) return hinfos->get(mhdr);
215 else return nil;
216 }
217
218
219 void preopt_init(void)
220 {
221 // `opt` not set at compile time in order to detect too-early usage
222 const char *failure = nil;
223 opt = &_objc_opt_data;
224
225 if (DisablePreopt) {
226 // OBJC_DISABLE_PREOPTIMIZATION is set
227 // If opt->version != VERSION then you continue at your own risk.
228 failure = "(by OBJC_DISABLE_PREOPTIMIZATION)";
229 }
230 else if (opt->version != objc_opt::VERSION) {
231 // This shouldn't happen. You probably forgot to edit objc-sel-table.s.
232 // If dyld really did write the wrong optimization version,
233 // then we must halt because we don't know what bits dyld twiddled.
234 _objc_fatal("bad objc preopt version (want %d, got %d)",
235 objc_opt::VERSION, opt->version);
236 }
237 else if (!opt->selopt() || !opt->headeropt()) {
238 // One of the tables is missing.
239 failure = "(dyld shared cache is absent or out of date)";
240 }
241 #if SUPPORT_IGNORED_SELECTOR_CONSTANT
242 else if (UseGC) {
243 // GC is on, which renames some selectors
244 // Non-selector optimizations are still valid, but we don't have
245 // any of those yet
246 failure = "(GC is on)";
247 }
248 #endif
249
250 if (failure) {
251 // All preoptimized selector references are invalid.
252 preoptimized = NO;
253 opt = nil;
254 disableSharedCacheOptimizations();
255
256 if (PrintPreopt) {
257 _objc_inform("PREOPTIMIZATION: is DISABLED %s", failure);
258 }
259 }
260 else {
261 // Valid optimization data written by dyld shared cache
262 preoptimized = YES;
263
264 if (PrintPreopt) {
265 _objc_inform("PREOPTIMIZATION: is ENABLED "
266 "(version %d)", opt->version);
267 }
268 }
269 }
270
271
272 __END_DECLS
273
274 // SUPPORT_PREOPT
275 #endif