2 * Copyright (c) 2012 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 Management of optimizations in the dyld shared cache
29 #include "objc-private.h"
33 // Preoptimization not supported on this platform.
37 bool isPreoptimized(void)
42 objc_selopt_t *preoptimizedSelectors(void)
47 Class getPreoptimizedClass(const char *name)
52 Class* copyPreoptimizedClasses(const char *name, int *outCount)
58 header_info *preoptimizedHinfoForHeader(const headerType *mhdr)
63 void preopt_init(void)
65 disableSharedCacheOptimizations();
68 _objc_inform("PREOPTIMIZATION: is DISABLED "
69 "(not supported on ths platform)");
78 #include <objc-shared-cache.h>
80 using objc_opt::objc_clsopt_t;
81 using objc_opt::objc_headeropt_t;
82 using objc_opt::objc_opt_t;
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()
90 static const objc_opt_t *opt = (objc_opt_t *)~0;
91 static bool preoptimized;
93 extern const objc_opt_t _objc_opt_data; // in __TEXT, __objc_opt_ro
95 bool isPreoptimized(void)
100 objc_selopt_t *preoptimizedSelectors(void)
102 return opt ? opt->selopt() : nil;
105 Class getPreoptimizedClass(const char *name)
107 objc_clsopt_t *classes = opt ? opt->clsopt() : nil;
108 if (!classes) return nil;
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
117 else if (count > 1) {
118 // more than one matching class - find one that is loaded
119 void *clslist[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];
129 // no match that is loaded
134 Class* copyPreoptimizedClasses(const char *name, int *outCount)
138 objc_clsopt_t *classes = opt ? opt->clsopt() : nil;
139 if (!classes) return nil;
143 uint32_t count = classes->getClassAndHeader(name, cls, hi);
144 if (count == 0) return nil;
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;
152 else if (count > 1) {
153 // more than one matching class - find those that are loaded
154 void *clslist[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];
163 if (*outCount == 0) {
164 // found multiple classes with that name, but none are loaded
171 // no match that is loaded
176 struct objc_headeropt_t {
179 header_info headers[0]; // sorted by mhdr address
181 header_info *get(const headerType *mhdr)
183 assert(entsize == sizeof(header_info));
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;
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)",
211 header_info *preoptimizedHinfoForHeader(const headerType *mhdr)
213 objc_headeropt_t *hinfos = opt ? opt->headeropt() : nil;
214 if (hinfos) return hinfos->get(mhdr);
219 void preopt_init(void)
221 // `opt` not set at compile time in order to detect too-early usage
222 const char *failure = nil;
223 opt = &_objc_opt_data;
226 // OBJC_DISABLE_PREOPTIMIZATION is set
227 // If opt->version != VERSION then you continue at your own risk.
228 failure = "(by OBJC_DISABLE_PREOPTIMIZATION)";
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);
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)";
241 #if SUPPORT_IGNORED_SELECTOR_CONSTANT
243 // GC is on, which renames some selectors
244 // Non-selector optimizations are still valid, but we don't have
246 failure = "(GC is on)";
251 // All preoptimized selector references are invalid.
254 disableSharedCacheOptimizations();
257 _objc_inform("PREOPTIMIZATION: is DISABLED %s", failure);
261 // Valid optimization data written by dyld shared cache
265 _objc_inform("PREOPTIMIZATION: is ENABLED "
266 "(version %d)", opt->version);