objc-opt.mm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  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. objc-opt.mm
  25. Management of optimizations in the dyld shared cache
  26. */
  27. #include "objc-private.h"
  28. #if !SUPPORT_PREOPT
  29. // Preoptimization not supported on this platform.
  30. struct objc_selopt_t;
  31. bool isPreoptimized(void)
  32. {
  33. return false;
  34. }
  35. bool noMissingWeakSuperclasses(void)
  36. {
  37. return false;
  38. }
  39. bool header_info::isPreoptimized() const
  40. {
  41. return false;
  42. }
  43. objc_selopt_t *preoptimizedSelectors(void)
  44. {
  45. return nil;
  46. }
  47. Protocol *getPreoptimizedProtocol(const char *name)
  48. {
  49. return nil;
  50. }
  51. unsigned int getPreoptimizedClassUnreasonableCount()
  52. {
  53. return 0;
  54. }
  55. Class getPreoptimizedClass(const char *name)
  56. {
  57. return nil;
  58. }
  59. Class* copyPreoptimizedClasses(const char *name, int *outCount)
  60. {
  61. *outCount = 0;
  62. return nil;
  63. }
  64. bool sharedRegionContains(const void *ptr)
  65. {
  66. return false;
  67. }
  68. header_info *preoptimizedHinfoForHeader(const headerType *mhdr)
  69. {
  70. return nil;
  71. }
  72. header_info_rw *getPreoptimizedHeaderRW(const struct header_info *const hdr)
  73. {
  74. return nil;
  75. }
  76. void preopt_init(void)
  77. {
  78. disableSharedCacheOptimizations();
  79. if (PrintPreopt) {
  80. _objc_inform("PREOPTIMIZATION: is DISABLED "
  81. "(not supported on ths platform)");
  82. }
  83. }
  84. // !SUPPORT_PREOPT
  85. #else
  86. // SUPPORT_PREOPT
  87. #include <objc-shared-cache.h>
  88. using objc_opt::objc_stringhash_offset_t;
  89. using objc_opt::objc_protocolopt_t;
  90. using objc_opt::objc_clsopt_t;
  91. using objc_opt::objc_headeropt_ro_t;
  92. using objc_opt::objc_headeropt_rw_t;
  93. using objc_opt::objc_opt_t;
  94. __BEGIN_DECLS
  95. // preopt: the actual opt used at runtime (nil or &_objc_opt_data)
  96. // _objc_opt_data: opt data possibly written by dyld
  97. // opt is initialized to ~0 to detect incorrect use before preopt_init()
  98. static const objc_opt_t *opt = (objc_opt_t *)~0;
  99. static uintptr_t shared_cache_start;
  100. static uintptr_t shared_cache_end;
  101. static bool preoptimized;
  102. extern const objc_opt_t _objc_opt_data; // in __TEXT, __objc_opt_ro
  103. /***********************************************************************
  104. * Return YES if we have a valid optimized shared cache.
  105. **********************************************************************/
  106. bool isPreoptimized(void)
  107. {
  108. return preoptimized;
  109. }
  110. /***********************************************************************
  111. * Return YES if the shared cache does not have any classes with
  112. * missing weak superclasses.
  113. **********************************************************************/
  114. bool noMissingWeakSuperclasses(void)
  115. {
  116. if (!preoptimized) return NO; // might have missing weak superclasses
  117. return opt->flags & objc_opt::NoMissingWeakSuperclasses;
  118. }
  119. /***********************************************************************
  120. * Return YES if this image's dyld shared cache optimizations are valid.
  121. **********************************************************************/
  122. bool header_info::isPreoptimized() const
  123. {
  124. // preoptimization disabled for some reason
  125. if (!preoptimized) return NO;
  126. // image not from shared cache, or not fixed inside shared cache
  127. if (!info()->optimizedByDyld()) return NO;
  128. return YES;
  129. }
  130. objc_selopt_t *preoptimizedSelectors(void)
  131. {
  132. return opt ? opt->selopt() : nil;
  133. }
  134. Protocol *getPreoptimizedProtocol(const char *name)
  135. {
  136. objc_protocolopt_t *protocols = opt ? opt->protocolopt() : nil;
  137. if (!protocols) return nil;
  138. return (Protocol *)protocols->getProtocol(name);
  139. }
  140. unsigned int getPreoptimizedClassUnreasonableCount()
  141. {
  142. objc_clsopt_t *classes = opt ? opt->clsopt() : nil;
  143. if (!classes) return 0;
  144. // This is an overestimate: each set of duplicates
  145. // gets double-counted in `capacity` as well.
  146. return classes->capacity + classes->duplicateCount();
  147. }
  148. Class getPreoptimizedClass(const char *name)
  149. {
  150. objc_clsopt_t *classes = opt ? opt->clsopt() : nil;
  151. if (!classes) return nil;
  152. void *cls;
  153. void *hi;
  154. uint32_t count = classes->getClassAndHeader(name, cls, hi);
  155. if (count == 1 && ((header_info *)hi)->isLoaded()) {
  156. // exactly one matching class, and its image is loaded
  157. return (Class)cls;
  158. }
  159. else if (count > 1) {
  160. // more than one matching class - find one that is loaded
  161. void *clslist[count];
  162. void *hilist[count];
  163. classes->getClassesAndHeaders(name, clslist, hilist);
  164. for (uint32_t i = 0; i < count; i++) {
  165. if (((header_info *)hilist[i])->isLoaded()) {
  166. return (Class)clslist[i];
  167. }
  168. }
  169. }
  170. // no match that is loaded
  171. return nil;
  172. }
  173. Class* copyPreoptimizedClasses(const char *name, int *outCount)
  174. {
  175. *outCount = 0;
  176. objc_clsopt_t *classes = opt ? opt->clsopt() : nil;
  177. if (!classes) return nil;
  178. void *cls;
  179. void *hi;
  180. uint32_t count = classes->getClassAndHeader(name, cls, hi);
  181. if (count == 0) return nil;
  182. Class *result = (Class *)calloc(count, sizeof(Class));
  183. if (count == 1 && ((header_info *)hi)->isLoaded()) {
  184. // exactly one matching class, and its image is loaded
  185. result[(*outCount)++] = (Class)cls;
  186. return result;
  187. }
  188. else if (count > 1) {
  189. // more than one matching class - find those that are loaded
  190. void *clslist[count];
  191. void *hilist[count];
  192. classes->getClassesAndHeaders(name, clslist, hilist);
  193. for (uint32_t i = 0; i < count; i++) {
  194. if (((header_info *)hilist[i])->isLoaded()) {
  195. result[(*outCount)++] = (Class)clslist[i];
  196. }
  197. }
  198. if (*outCount == 0) {
  199. // found multiple classes with that name, but none are loaded
  200. free(result);
  201. result = nil;
  202. }
  203. return result;
  204. }
  205. // no match that is loaded
  206. return nil;
  207. }
  208. /***********************************************************************
  209. * Return YES if the given pointer lies within the shared cache.
  210. * If the shared cache is not set up or is not valid,
  211. **********************************************************************/
  212. bool sharedRegionContains(const void *ptr)
  213. {
  214. uintptr_t address = (uintptr_t)ptr;
  215. return shared_cache_start <= address && address < shared_cache_end;
  216. }
  217. namespace objc_opt {
  218. struct objc_headeropt_ro_t {
  219. uint32_t count;
  220. uint32_t entsize;
  221. header_info headers[0]; // sorted by mhdr address
  222. header_info *get(const headerType *mhdr)
  223. {
  224. assert(entsize == sizeof(header_info));
  225. int32_t start = 0;
  226. int32_t end = count;
  227. while (start <= end) {
  228. int32_t i = (start+end)/2;
  229. header_info *hi = headers+i;
  230. if (mhdr == hi->mhdr()) return hi;
  231. else if (mhdr < hi->mhdr()) end = i-1;
  232. else start = i+1;
  233. }
  234. #if DEBUG
  235. for (uint32_t i = 0; i < count; i++) {
  236. header_info *hi = headers+i;
  237. if (mhdr == hi->mhdr()) {
  238. _objc_fatal("failed to find header %p (%d/%d)",
  239. mhdr, i, count);
  240. }
  241. }
  242. #endif
  243. return nil;
  244. }
  245. };
  246. struct objc_headeropt_rw_t {
  247. uint32_t count;
  248. uint32_t entsize;
  249. header_info_rw headers[0]; // sorted by mhdr address
  250. };
  251. };
  252. header_info *preoptimizedHinfoForHeader(const headerType *mhdr)
  253. {
  254. #if !__OBJC2__
  255. // fixme old ABI shared cache doesn't prepare these properly
  256. return nil;
  257. #endif
  258. objc_headeropt_ro_t *hinfos = opt ? opt->headeropt_ro() : nil;
  259. if (hinfos) return hinfos->get(mhdr);
  260. else return nil;
  261. }
  262. header_info_rw *getPreoptimizedHeaderRW(const struct header_info *const hdr)
  263. {
  264. #if !__OBJC2__
  265. // fixme old ABI shared cache doesn't prepare these properly
  266. return nil;
  267. #endif
  268. objc_headeropt_ro_t *hinfoRO = opt ? opt->headeropt_ro() : nil;
  269. objc_headeropt_rw_t *hinfoRW = opt ? opt->headeropt_rw() : nil;
  270. if (!hinfoRO || !hinfoRW) {
  271. _objc_fatal("preoptimized header_info missing for %s (%p %p %p)",
  272. hdr->fname(), hdr, hinfoRO, hinfoRW);
  273. }
  274. int32_t index = (int32_t)(hdr - hinfoRO->headers);
  275. assert(hinfoRW->entsize == sizeof(header_info_rw));
  276. return &hinfoRW->headers[index];
  277. }
  278. void preopt_init(void)
  279. {
  280. // Get the memory region occupied by the shared cache.
  281. size_t length;
  282. const void *start = _dyld_get_shared_cache_range(&length);
  283. if (start) {
  284. shared_cache_start = (uintptr_t)start;
  285. shared_cache_end = shared_cache_start + length;
  286. } else {
  287. shared_cache_start = shared_cache_end = 0;
  288. }
  289. // `opt` not set at compile time in order to detect too-early usage
  290. const char *failure = nil;
  291. opt = &_objc_opt_data;
  292. if (DisablePreopt) {
  293. // OBJC_DISABLE_PREOPTIMIZATION is set
  294. // If opt->version != VERSION then you continue at your own risk.
  295. failure = "(by OBJC_DISABLE_PREOPTIMIZATION)";
  296. }
  297. else if (opt->version != objc_opt::VERSION) {
  298. // This shouldn't happen. You probably forgot to edit objc-sel-table.s.
  299. // If dyld really did write the wrong optimization version,
  300. // then we must halt because we don't know what bits dyld twiddled.
  301. _objc_fatal("bad objc preopt version (want %d, got %d)",
  302. objc_opt::VERSION, opt->version);
  303. }
  304. else if (!opt->selopt() || !opt->headeropt_ro()) {
  305. // One of the tables is missing.
  306. failure = "(dyld shared cache is absent or out of date)";
  307. }
  308. if (failure) {
  309. // All preoptimized selector references are invalid.
  310. preoptimized = NO;
  311. opt = nil;
  312. disableSharedCacheOptimizations();
  313. if (PrintPreopt) {
  314. _objc_inform("PREOPTIMIZATION: is DISABLED %s", failure);
  315. }
  316. }
  317. else {
  318. // Valid optimization data written by dyld shared cache
  319. preoptimized = YES;
  320. if (PrintPreopt) {
  321. _objc_inform("PREOPTIMIZATION: is ENABLED "
  322. "(version %d)", opt->version);
  323. }
  324. }
  325. }
  326. __END_DECLS
  327. // SUPPORT_PREOPT
  328. #endif