]> git.saurik.com Git - apple/dyld.git/blame_incremental - launch-cache/ObjCModernAbstraction.hpp
dyld-353.2.3.tar.gz
[apple/dyld.git] / launch-cache / ObjCModernAbstraction.hpp
... / ...
CommitLineData
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include "MachOLayout.hpp"
26#include <iterator>
27#include <deque>
28
29// iterate an entsize-based list
30// typedef entsize_iterator< A, type_t<A>, type_list_t<A> > type_iterator;
31template <typename A, typename T, typename Tlist>
32struct entsize_iterator {
33 uint32_t entsize;
34 uint32_t index; // keeping track of this saves a divide in operator-
35 T* current;
36
37 typedef std::random_access_iterator_tag iterator_category;
38 typedef T value_type;
39 typedef ptrdiff_t difference_type;
40 typedef T* pointer;
41 typedef T& reference;
42
43 entsize_iterator() { }
44
45 entsize_iterator(const Tlist& list, uint32_t start = 0)
46 : entsize(list.getEntsize()), index(start), current(&list.get(start))
47 { }
48
49 const entsize_iterator<A,T,Tlist>& operator += (ptrdiff_t count) {
50 current = (T*)((uint8_t *)current + count*entsize);
51 index += count;
52 return *this;
53 }
54 const entsize_iterator<A,T,Tlist>& operator -= (ptrdiff_t count) {
55 current = (T*)((uint8_t *)current - count*entsize);
56 index -= count;
57 return *this;
58 }
59 const entsize_iterator<A,T,Tlist> operator + (ptrdiff_t count) const {
60 return entsize_iterator(*this) += count;
61 }
62 const entsize_iterator<A,T,Tlist> operator - (ptrdiff_t count) const {
63 return entsize_iterator(*this) -= count;
64 }
65
66 entsize_iterator<A,T,Tlist>& operator ++ () { *this += 1; return *this; }
67 entsize_iterator<A,T,Tlist>& operator -- () { *this -= 1; return *this; }
68 entsize_iterator<A,T,Tlist> operator ++ (int) {
69 entsize_iterator<A,T,Tlist> result(*this); *this += 1; return result;
70 }
71 entsize_iterator<A,T,Tlist> operator -- (int) {
72 entsize_iterator<A,T,Tlist> result(*this); *this -= 1; return result;
73 }
74
75 ptrdiff_t operator - (const entsize_iterator<A,T,Tlist>& rhs) const {
76 return (ptrdiff_t)this->index - (ptrdiff_t)rhs.index;
77 }
78
79 T& operator * () { return *current; }
80 T& operator * () const { return *current; }
81 T& operator -> () { return *current; }
82 const T& operator -> () const { return *current; }
83
84 operator T& () const { return *current; }
85
86 bool operator == (const entsize_iterator<A,T,Tlist>& rhs) {
87 return this->current == rhs.current;
88 }
89 bool operator != (const entsize_iterator<A,T,Tlist>& rhs) {
90 return this->current != rhs.current;
91 }
92
93 bool operator < (const entsize_iterator<A,T,Tlist>& rhs) {
94 return this->current < rhs.current;
95 }
96 bool operator > (const entsize_iterator<A,T,Tlist>& rhs) {
97 return this->current > rhs.current;
98 }
99
100
101 static void overwrite(entsize_iterator<A,T,Tlist>& dst, const Tlist* srcList)
102 {
103 entsize_iterator<A,T,Tlist> src;
104 uint32_t ee = srcList->getEntsize();
105 for (src = srcList->begin(); src != srcList->end(); ++src) {
106 memcpy(&*dst, &*src, ee);
107 ++dst;
108 }
109 }
110};
111
112template <typename A>
113class objc_header_info_t {
114
115 typedef typename A::P P;
116 typedef typename A::P::uint_t pint_t;
117
118 pint_t next; // objc_header_info *
119 pint_t mhdr; // mach_header or mach_header_64
120 pint_t info; // objc_image_info *
121 pint_t fname; // const char *
122 bool loaded;
123 bool inSharedCache;
124 bool allClassesRealized;
125
126public:
127 objc_header_info_t(SharedCache<A>* cache, const macho_header<P>* mh)
128 : next(0),
129 mhdr(0),
130 info(0),
131 fname(0),
132 loaded(0),
133 allClassesRealized(0)
134 {
135 A::P::setP(mhdr, cache->VMAddressForMappedAddress(mh));
136 const macho_section<P>* sect = mh->getSection("__DATA", "__objc_imageinfo");
137 if (sect) A::P::setP(info, sect->addr());
138
139 // can't set fname because dyld sometimes edits it
140 }
141
142 void addPointers(std::vector<void*>& pointersToAdd) {
143 pointersToAdd.push_back(&mhdr);
144 if (info) pointersToAdd.push_back(&info);
145 }
146
147 uint64_t header_vmaddr() const { return mhdr; }
148};
149
150template <typename A> class objc_method_list_t; // forward reference
151
152template <typename A>
153class objc_method_t {
154 typename A::P::uint_t name; // SEL
155 typename A::P::uint_t types; // const char *
156 typename A::P::uint_t imp; // IMP
157 friend class objc_method_list_t<A>;
158public:
159 typename A::P::uint_t getName() const { return A::P::getP(name); }
160 void setName(typename A::P::uint_t newName) { A::P::setP(name, newName); }
161
162 struct SortBySELAddress :
163 public std::binary_function<const objc_method_t<A>&,
164 const objc_method_t<A>&, bool>
165 {
166 bool operator() (const objc_method_t<A>& lhs,
167 const objc_method_t<A>& rhs)
168 {
169 return lhs.getName() < rhs.getName();
170 }
171 };
172};
173
174template <typename A>
175class objc_method_list_t {
176 uint32_t entsize;
177 uint32_t count;
178 objc_method_t<A> first;
179
180 void* operator new (size_t, void* buf) { return buf; }
181
182public:
183
184 typedef entsize_iterator< A, objc_method_t<A>, objc_method_list_t<A> > method_iterator;
185
186 uint32_t getCount() const { return A::P::E::get32(count); }
187
188 uint32_t getEntsize() const {return A::P::E::get32(entsize)&~(uint32_t)3;}
189
190 objc_method_t<A>& get(uint32_t i) const { return *(objc_method_t<A> *)((uint8_t *)&first + i * getEntsize()); }
191
192 uint32_t byteSize() const {
193 return byteSizeForCount(getCount(), getEntsize());
194 }
195
196 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_method_t<A>)) {
197 return sizeof(objc_method_list_t<A>) - sizeof(objc_method_t<A>) + c*e;
198 }
199
200 method_iterator begin() { return method_iterator(*this, 0); }
201 method_iterator end() { return method_iterator(*this, getCount()); }
202 const method_iterator begin() const { return method_iterator(*this, 0); }
203 const method_iterator end() const { return method_iterator(*this, getCount()); }
204
205 void setFixedUp() { A::P::E::set32(entsize, getEntsize() | 3); }
206
207 void getPointers(std::set<void*>& pointersToRemove) {
208 for(method_iterator it = begin(); it != end(); ++it) {
209 objc_method_t<A>& entry = *it;
210 pointersToRemove.insert(&(entry.name));
211 pointersToRemove.insert(&(entry.types));
212 pointersToRemove.insert(&(entry.imp));
213 }
214 }
215
216 static void addPointers(uint8_t* methodList, std::vector<void*>& pointersToAdd) {
217 objc_method_list_t<A>* mlist = (objc_method_list_t<A>*)methodList;
218 for(method_iterator it = mlist->begin(); it != mlist->end(); ++it) {
219 objc_method_t<A>& entry = *it;
220 pointersToAdd.push_back(&(entry.name));
221 pointersToAdd.push_back(&(entry.types));
222 pointersToAdd.push_back(&(entry.imp));
223 }
224 }
225
226 static objc_method_list_t<A>* newMethodList(size_t newCount, uint32_t newEntsize) {
227 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
228 return new (buf) objc_method_list_t<A>(newCount, newEntsize);
229 }
230
231 void operator delete(void * p) {
232 ::free(p);
233 }
234
235 objc_method_list_t(uint32_t newCount,
236 uint32_t newEntsize = sizeof(objc_method_t<A>))
237 : entsize(newEntsize), count(newCount)
238 { }
239
240private:
241 // use newMethodList instead
242 void* operator new (size_t);
243};
244
245
246// Ivar offset variables are 64-bit on x86_64 and 32-bit everywhere else.
247
248template <typename A>
249class objc_ivar_offset_t {
250 typedef typename A::P::uint_t pint_t;
251 typename A::P::uint_t ptr; // uint32_t *
252
253 uint32_t& offset(SharedCache<A> *cache) const { return *(uint32_t *)cache->mappedAddressForVMAddress(A::P::getP(ptr)); }
254
255public:
256 bool hasOffset() const { return A::P::getP(ptr) != 0; }
257 pint_t getOffset(SharedCache<A> *cache) const { return A::P::E::get32(offset(cache)); }
258 void setOffset(SharedCache<A> *cache, pint_t newOffset) { A::P::E::set32(offset(cache), newOffset); }
259};
260
261template <>
262class objc_ivar_offset_t<x86_64> {
263 typedef x86_64 A;
264 typedef typename A::P::uint_t pint_t;
265 typename A::P::uint_t ptr; // uint64_t *
266
267 uint64_t& offset(SharedCache<A> *cache) const { return *(uint64_t *)cache->mappedAddressForVMAddress(A::P::getP(ptr)); }
268
269public:
270 bool hasOffset() const { return A::P::getP(ptr) != 0; }
271 pint_t getOffset(SharedCache<A> *cache) const { return A::P::E::get64(offset(cache)); }
272 void setOffset(SharedCache<A> *cache, pint_t newOffset) { A::P::E::set64(offset(cache), newOffset); }
273};
274
275template <typename A>
276class objc_ivar_t {
277 typedef typename A::P::uint_t pint_t;
278 objc_ivar_offset_t<A> offset; // uint32_t * (uint64_t * on x86_64)
279 typename A::P::uint_t name; // const char *
280 typename A::P::uint_t type; // const char *
281 uint32_t alignment;
282 uint32_t size;
283
284public:
285 const char * getName(SharedCache<A> *cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
286
287 bool hasOffset() const { return offset.hasOffset(); }
288 pint_t getOffset(SharedCache<A> *cache) const { return offset.getOffset(cache); }
289 void setOffset(SharedCache<A> *cache, pint_t newOffset) { offset.setOffset(cache, newOffset); }
290
291 uint32_t getAlignment()
292 {
293 uint32_t a = A::P::E::get32(alignment);
294 return a == (uint32_t)-1 ? sizeof(typename A::P::uint_t) : 1<<a;
295 }
296};
297
298template <typename A>
299class objc_ivar_list_t {
300 typedef typename A::P::uint_t pint_t;
301 uint32_t entsize;
302 uint32_t count;
303 objc_ivar_t<A> first;
304
305 void* operator new (size_t, void* buf) { return buf; }
306
307public:
308
309 typedef entsize_iterator< A, objc_ivar_t<A>, objc_ivar_list_t<A> > ivar_iterator;
310
311 uint32_t getCount() const { return A::P::E::get32(count); }
312
313 uint32_t getEntsize() const { return A::P::E::get32(entsize); }
314
315 objc_ivar_t<A>& get(pint_t i) const { return *(objc_ivar_t<A> *)((uint8_t *)&first + i * A::P::E::get32(entsize)); }
316
317 uint32_t byteSize() const {
318 return byteSizeForCount(getCount(), getEntsize());
319 }
320
321 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_ivar_t<A>)) {
322 return sizeof(objc_ivar_list_t<A>) - sizeof(objc_ivar_t<A>) + c*e;
323 }
324
325 ivar_iterator begin() { return ivar_iterator(*this, 0); }
326 ivar_iterator end() { return ivar_iterator(*this, getCount()); }
327 const ivar_iterator begin() const { return ivar_iterator(*this, 0); }
328 const ivar_iterator end() const { return ivar_iterator(*this, getCount()); }
329
330 static objc_ivar_list_t<A>* newIvarList(size_t newCount, uint32_t newEntsize) {
331 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
332 return new (buf) objc_ivar_list_t<A>(newCount, newEntsize);
333 }
334
335 void operator delete(void * p) {
336 ::free(p);
337 }
338
339 objc_ivar_list_t(uint32_t newCount,
340 uint32_t newEntsize = sizeof(objc_ivar_t<A>))
341 : entsize(newEntsize), count(newCount)
342 { }
343private:
344 // use newIvarList instead
345 void* operator new (size_t);
346};
347
348
349template <typename A> class objc_property_list_t; // forward
350
351template <typename A>
352class objc_property_t {
353 typename A::P::uint_t name;
354 typename A::P::uint_t attributes;
355 friend class objc_property_list_t<A>;
356public:
357
358 const char * getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
359
360 const char * getAttributes(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(attributes)); }
361};
362
363template <typename A>
364class objc_property_list_t {
365 uint32_t entsize;
366 uint32_t count;
367 objc_property_t<A> first;
368
369 void* operator new (size_t, void* buf) { return buf; }
370
371public:
372
373 typedef entsize_iterator< A, objc_property_t<A>, objc_property_list_t<A> > property_iterator;
374
375 uint32_t getCount() const { return A::P::E::get32(count); }
376
377 uint32_t getEntsize() const { return A::P::E::get32(entsize); }
378
379 objc_property_t<A>& get(uint32_t i) const { return *(objc_property_t<A> *)((uint8_t *)&first + i * getEntsize()); }
380
381 uint32_t byteSize() const {
382 return byteSizeForCount(getCount(), getEntsize());
383 }
384
385 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_property_t<A>)) {
386 return sizeof(objc_property_list_t<A>) - sizeof(objc_property_t<A>) + c*e;
387 }
388
389 property_iterator begin() { return property_iterator(*this, 0); }
390 property_iterator end() { return property_iterator(*this, getCount()); }
391 const property_iterator begin() const { return property_iterator(*this, 0); }
392 const property_iterator end() const { return property_iterator(*this, getCount()); }
393
394 void getPointers(std::set<void*>& pointersToRemove) {
395 for(property_iterator it = begin(); it != end(); ++it) {
396 objc_property_t<A>& entry = *it;
397 pointersToRemove.insert(&(entry.name));
398 pointersToRemove.insert(&(entry.attributes));
399 }
400 }
401
402 static void addPointers(uint8_t* propertyList, std::vector<void*>& pointersToAdd) {
403 objc_property_list_t<A>* plist = (objc_property_list_t<A>*)propertyList;
404 for(property_iterator it = plist->begin(); it != plist->end(); ++it) {
405 objc_property_t<A>& entry = *it;
406 pointersToAdd.push_back(&(entry.name));
407 pointersToAdd.push_back(&(entry.attributes));
408 }
409 }
410
411 static objc_property_list_t<A>* newPropertyList(size_t newCount, uint32_t newEntsize) {
412 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
413 return new (buf) objc_property_list_t<A>(newCount, newEntsize);
414 }
415
416 void operator delete(void * p) {
417 ::free(p);
418 }
419
420 objc_property_list_t(uint32_t newCount,
421 uint32_t newEntsize = sizeof(objc_property_t<A>))
422 : entsize(newEntsize), count(newCount)
423 { }
424private:
425 // use newPropertyList instead
426 void* operator new (size_t);
427};
428
429template <typename A>
430class objc_protocol_t {
431 typename A::P::uint_t isa;
432 typename A::P::uint_t name;
433 typename A::P::uint_t protocols;
434 typename A::P::uint_t instanceMethods;
435 typename A::P::uint_t classMethods;
436 typename A::P::uint_t optionalInstanceMethods;
437 typename A::P::uint_t optionalClassMethods;
438 typename A::P::uint_t instanceProperties;
439
440public:
441 objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceMethods)); }
442
443 objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(classMethods)); }
444
445 objc_method_list_t<A> *getOptionalInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(optionalInstanceMethods)); }
446
447 objc_method_list_t<A> *getOptionalClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(optionalClassMethods)); }
448
449};
450
451template <typename A>
452class objc_protocol_list_t {
453 typedef typename A::P::uint_t pint_t;
454 pint_t count;
455 pint_t list[0];
456
457 void* operator new (size_t, void* buf) { return buf; }
458
459public:
460
461 pint_t getCount() const { return A::P::getP(count); }
462
463 objc_protocol_t<A>* get(SharedCache<A>* cache, pint_t i) {
464 return (objc_protocol_t<A>*)cache->mappedAddressForVMAddress(A::P::getP(list[i]));
465 }
466
467 void overwrite(pint_t& index, const objc_protocol_list_t<A>* src) {
468 pint_t srcCount = src->getCount();
469 memcpy(list+index, src->list, srcCount * sizeof(pint_t));
470 index += srcCount;
471 }
472
473 uint32_t byteSize() const {
474 return byteSizeForCount(getCount());
475 }
476 static uint32_t byteSizeForCount(pint_t c) {
477 return sizeof(objc_protocol_list_t<A>) + c*sizeof(pint_t);
478 }
479
480 void getPointers(std::set<void*>& pointersToRemove) {
481 for(int i=0 ; i < count; ++i) {
482 pointersToRemove.insert(&list[i]);
483 }
484 }
485
486 static void addPointers(uint8_t* protocolList, std::vector<void*>& pointersToAdd) {
487 objc_protocol_list_t<A>* plist = (objc_protocol_list_t<A>*)protocolList;
488 for(int i=0 ; i < plist->count; ++i) {
489 pointersToAdd.push_back(&plist->list[i]);
490 }
491 }
492
493 static objc_protocol_list_t<A>* newProtocolList(pint_t newCount) {
494 void *buf = ::calloc(byteSizeForCount(newCount), 1);
495 return new (buf) objc_protocol_list_t<A>(newCount);
496 }
497
498 void operator delete(void * p) {
499 ::free(p);
500 }
501
502 objc_protocol_list_t(uint32_t newCount) : count(newCount) { }
503private:
504 // use newProtocolList instead
505 void* operator new (size_t);
506};
507
508
509template <typename A>
510class objc_class_data_t {
511 uint32_t flags;
512 uint32_t instanceStart;
513 // Note there is 4-bytes of alignment padding between instanceSize and ivarLayout
514 // on 64-bit archs, but no padding on 32-bit archs.
515 // This union is a way to model that.
516 union {
517 uint32_t instanceSize;
518 typename A::P::uint_t pad;
519 } instanceSize;
520 typename A::P::uint_t ivarLayout;
521 typename A::P::uint_t name;
522 typename A::P::uint_t baseMethods;
523 typename A::P::uint_t baseProtocols;
524 typename A::P::uint_t ivars;
525 typename A::P::uint_t weakIvarLayout;
526 typename A::P::uint_t baseProperties;
527
528public:
529 bool isMetaClass() { return A::P::E::get32(flags) & 1; }
530
531 uint32_t getInstanceStart() { return A::P::E::get32(instanceStart); }
532 void setInstanceStart(uint32_t newStart) { A::P::E::set32(instanceStart, newStart); }
533
534 uint32_t getInstanceSize() { return A::P::E::get32(instanceSize.instanceSize); }
535 void setInstanceSize(uint32_t newSiz) { A::P::E::set32(instanceSize.instanceSize, newSiz); }
536
537 objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseMethods)); }
538
539 objc_protocol_list_t<A> *getProtocolList(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProtocols)); }
540
541 objc_ivar_list_t<A> *getIvarList(SharedCache<A>* cache) const { return (objc_ivar_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(ivars)); }
542
543 objc_property_list_t<A> *getPropertyList(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProperties)); }
544
545 const char * getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
546
547 void setMethodList(SharedCache<A>* cache, objc_method_list_t<A>* mlist) {
548 A::P::setP(baseMethods, cache->VMAddressForMappedAddress(mlist));
549 }
550
551 void setProtocolList(SharedCache<A>* cache, objc_protocol_list_t<A>* protolist) {
552 A::P::setP(baseProtocols, cache->VMAddressForMappedAddress(protolist));
553 }
554
555 void setPropertyList(SharedCache<A>* cache, objc_property_list_t<A>* proplist) {
556 A::P::setP(baseProperties, cache->VMAddressForMappedAddress(proplist));
557 }
558
559 void addMethodListPointer(std::vector<void*>& pointersToAdd) {
560 pointersToAdd.push_back(&this->baseMethods);
561 }
562
563 void addPropertyListPointer(std::vector<void*>& pointersToAdd) {
564 pointersToAdd.push_back(&this->baseProperties);
565 }
566
567 void addProtocolListPointer(std::vector<void*>& pointersToAdd) {
568 pointersToAdd.push_back(&this->baseProtocols);
569 }
570};
571
572template <typename A>
573class objc_class_t {
574 typename A::P::uint_t isa;
575 typename A::P::uint_t superclass;
576 typename A::P::uint_t method_cache;
577 typename A::P::uint_t vtable;
578 typename A::P::uint_t data;
579
580public:
581 bool isMetaClass(SharedCache<A>* cache) const { return getData(cache)->isMetaClass(); }
582
583 objc_class_t<A> *getIsa(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(isa)); }
584
585 objc_class_t<A> *getSuperclass(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(superclass)); }
586
587 objc_class_data_t<A> *getData(SharedCache<A>* cache) const { return (objc_class_data_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(data)); }
588
589 objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return getData(cache)->getMethodList(cache); }
590
591 objc_protocol_list_t<A> *getProtocolList(SharedCache<A>* cache) const { return getData(cache)->getProtocolList(cache); }
592
593 objc_property_list_t<A> *getPropertyList(SharedCache<A>* cache) const { return getData(cache)->getPropertyList(cache); }
594
595 const char * getName(SharedCache<A>* cache) const {
596 return getData(cache)->getName(cache);
597 }
598
599 void setMethodList(SharedCache<A>* cache, objc_method_list_t<A>* mlist) {
600 getData(cache)->setMethodList(cache, mlist);
601 }
602
603 void setProtocolList(SharedCache<A>* cache, objc_protocol_list_t<A>* protolist) {
604 getData(cache)->setProtocolList(cache, protolist);
605 }
606
607 void setPropertyList(SharedCache<A>* cache, objc_property_list_t<A>* proplist) {
608 getData(cache)->setPropertyList(cache, proplist);
609 }
610
611 void addMethodListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
612 getData(cache)->addMethodListPointer(pointersToAdd);
613 }
614
615 void addPropertyListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
616 getData(cache)->addPropertyListPointer(pointersToAdd);
617 }
618
619 void addProtocolListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
620 getData(cache)->addProtocolListPointer(pointersToAdd);
621 }
622
623};
624
625
626
627template <typename A>
628class objc_category_t {
629 typename A::P::uint_t name;
630 typename A::P::uint_t cls;
631 typename A::P::uint_t instanceMethods;
632 typename A::P::uint_t classMethods;
633 typename A::P::uint_t protocols;
634 typename A::P::uint_t instanceProperties;
635
636public:
637
638 const char * getName(SharedCache<A> *cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
639
640 objc_class_t<A> *getClass(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(cls)); }
641
642 objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceMethods)); }
643
644 objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(classMethods)); }
645
646 objc_protocol_list_t<A> *getProtocols(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(protocols)); }
647
648 objc_property_list_t<A> *getInstanceProperties(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceProperties)); }
649
650 void getPointers(std::set<void*>& pointersToRemove) {
651 pointersToRemove.insert(&name);
652 pointersToRemove.insert(&cls);
653 pointersToRemove.insert(&instanceMethods);
654 pointersToRemove.insert(&classMethods);
655 pointersToRemove.insert(&protocols);
656 pointersToRemove.insert(&instanceProperties);
657 }
658
659
660};
661
662template <typename A>
663class objc_message_ref_t {
664 typename A::P::uint_t imp;
665 typename A::P::uint_t sel;
666
667public:
668 typename A::P::uint_t getName() const { return A::P::getP(sel); }
669
670 void setName(typename A::P::uint_t newName) { A::P::setP(sel, newName); }
671};
672
673// Call visitor.visitIvar() on every ivar in a given class.
674template <typename A, typename V>
675class IvarWalker {
676 typedef typename A::P P;
677 typedef typename A::P::uint_t pint_t;
678 V& ivarVisitor;
679public:
680
681 IvarWalker(V& visitor) : ivarVisitor(visitor) { }
682
683 void walk(SharedCache<A>* cache, const macho_header<P>* header, objc_class_t<A> *cls)
684 {
685 objc_class_data_t<A> *data = cls->getData(cache);
686 objc_ivar_list_t<A> *ivars = data->getIvarList(cache);
687 if (ivars) {
688 for (pint_t i = 0; i < ivars->getCount(); i++) {
689 objc_ivar_t<A>& ivar = ivars->get(i);
690 //fprintf(stderr, "visiting ivar: %s\n", ivar.getName(cache));
691 ivarVisitor.visitIvar(cache, header, cls, &ivar);
692 }
693 } else {
694 //fprintf(stderr, "no ivars\n");
695 }
696 }
697
698 void visitClass(SharedCache<A>* cache, const macho_header<P>* header, objc_class_t<A> *cls)
699 {
700 walk(cache, header, cls);
701 }
702};
703
704// Call visitor.visitClass() on every class.
705template <typename A, typename V>
706class ClassWalker {
707 typedef typename A::P P;
708 typedef typename A::P::uint_t pint_t;
709 V& classVisitor;
710public:
711
712 ClassWalker(V& visitor) : classVisitor(visitor) { }
713
714 void walk(SharedCache<A>* cache, const macho_header<P>* header)
715 {
716 PointerSection<A, objc_class_t<A> *>
717 classes(cache, header, "__DATA", "__objc_classlist");
718
719 for (pint_t i = 0; i < classes.count(); i++) {
720 objc_class_t<A> *cls = classes.get(i);
721 //fprintf(stderr, "visiting class: %s\n", cls->getName(cache));
722 classVisitor.visitClass(cache, header, cls);
723 }
724 }
725};
726
727
728// Call visitor.visitMethodList(mlist) on every method list in a header.
729template <typename A, typename V>
730class MethodListWalker {
731
732 typedef typename A::P P;
733 typedef typename A::P::uint_t pint_t;
734
735 V& mVisitor;
736
737public:
738
739 MethodListWalker(V& visitor) : mVisitor(visitor) { }
740
741 void walk(SharedCache<A>* cache, const macho_header<P>* header, bool walkProtocols)
742 {
743 // Method lists in classes
744 PointerSection<A, objc_class_t<A> *>
745 classes(cache, header, "__DATA", "__objc_classlist");
746
747 for (pint_t i = 0; i < classes.count(); i++) {
748 objc_class_t<A> *cls = classes.get(i);
749 objc_method_list_t<A> *mlist;
750 if ((mlist = cls->getMethodList(cache))) {
751 mVisitor.visitMethodList(mlist);
752 }
753 if ((mlist = cls->getIsa(cache)->getMethodList(cache))) {
754 mVisitor.visitMethodList(mlist);
755 }
756 }
757
758 // Method lists from categories
759 PointerSection<A, objc_category_t<A> *>
760 cats(cache, header, "__DATA", "__objc_catlist");
761 for (pint_t i = 0; i < cats.count(); i++) {
762 objc_category_t<A> *cat = cats.get(i);
763 objc_method_list_t<A> *mlist;
764 if ((mlist = cat->getInstanceMethods(cache))) {
765 mVisitor.visitMethodList(mlist);
766 }
767 if ((mlist = cat->getClassMethods(cache))) {
768 mVisitor.visitMethodList(mlist);
769 }
770 }
771
772 // Method description lists from protocols
773 if ( walkProtocols ) {
774 PointerSection<A, objc_protocol_t<A> *>
775 protocols(cache, header, "__DATA", "__objc_protolist");
776 for (pint_t i = 0; i < protocols.count(); i++) {
777 objc_protocol_t<A> *proto = protocols.get(i);
778 objc_method_list_t<A> *mlist;
779 if ((mlist = proto->getInstanceMethods(cache))) {
780 mVisitor.visitMethodList(mlist);
781 }
782 if ((mlist = proto->getClassMethods(cache))) {
783 mVisitor.visitMethodList(mlist);
784 }
785 if ((mlist = proto->getOptionalInstanceMethods(cache))) {
786 mVisitor.visitMethodList(mlist);
787 }
788 if ((mlist = proto->getOptionalClassMethods(cache))) {
789 mVisitor.visitMethodList(mlist);
790 }
791 }
792 }
793 }
794};
795
796
797// Update selector references. The visitor performs recording and uniquing.
798template <typename A, typename V>
799class SelectorOptimizer {
800
801 typedef typename A::P P;
802 typedef typename A::P::uint_t pint_t;
803
804 V& mVisitor;
805
806 friend class MethodListWalker< A, SelectorOptimizer<A,V> >;
807 void visitMethodList(objc_method_list_t<A> *mlist)
808 {
809 // Gather selectors. Update method names.
810 for (pint_t m = 0; m < mlist->getCount(); m++) {
811 pint_t oldValue = mlist->get(m).getName();
812 pint_t newValue = mVisitor.visit(oldValue);
813 mlist->get(m).setName(newValue);
814 }
815 // Do not setFixedUp: the methods are not yet sorted.
816 }
817
818public:
819
820 SelectorOptimizer(V& visitor) : mVisitor(visitor) { }
821
822 void optimize(SharedCache<A>* cache, const macho_header<P>* header)
823 {
824 // method lists of all kinds
825 MethodListWalker< A, SelectorOptimizer<A,V> > mw(*this);
826 mw.walk(cache, header, true);
827
828 // @selector references
829 PointerSection<A, const char *>
830 selrefs(cache, header, "__DATA", "__objc_selrefs");
831 for (pint_t i = 0; i < selrefs.count(); i++) {
832 pint_t oldValue = selrefs.getUnmapped(i);
833 pint_t newValue = mVisitor.visit(oldValue);
834 selrefs.set(i, newValue);
835 }
836
837 // message references
838 ArraySection<A, objc_message_ref_t<A> >
839 msgrefs(cache, header, "__DATA", "__objc_msgrefs");
840 for (pint_t i = 0; i < msgrefs.count(); i++) {
841 objc_message_ref_t<A>& msg = msgrefs.get(i);
842 pint_t oldValue = msg.getName();
843 pint_t newValue = mVisitor.visit(oldValue);
844 msg.setName(newValue);
845 }
846 }
847};
848
849
850// Update selector references. The visitor performs recording and uniquing.
851template <typename A>
852class IvarOffsetOptimizer {
853 typedef typename A::P P;
854
855 uint32_t slide;
856 uint32_t maxAlignment;
857
858 uint32_t fOptimized;
859
860public:
861
862 IvarOffsetOptimizer() : fOptimized(0) { }
863
864 size_t optimized() const { return fOptimized; }
865
866 // dual purpose ivar visitor function
867 // if slide!=0 then slides the ivar by that amount, otherwise computes maxAlignment
868 void visitIvar(SharedCache<A>* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<A> *cls, objc_ivar_t<A> *ivar)
869 {
870 if (slide == 0) {
871 uint32_t alignment = ivar->getAlignment();
872 if (alignment > maxAlignment) maxAlignment = alignment;
873 } else {
874 // skip anonymous bitfields
875 if (ivar->hasOffset()) {
876 uint32_t oldOffset = (uint32_t)ivar->getOffset(cache);
877 ivar->setOffset(cache, oldOffset + slide);
878 fOptimized++;
879 //fprintf(stderr, "%d -> %d for %s.%s\n", oldOffset, oldOffset + slide, cls->getName(cache), ivar->getName(cache));
880 } else {
881 //fprintf(stderr, "NULL offset\n");
882 }
883 }
884 }
885
886 // Class visitor function. Evaluates whether to slide ivars and performs slide if needed.
887 // The slide algorithm is also implemented in objc. Any changes here should be reflected there also.
888 void visitClass(SharedCache<A>* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<A> *cls)
889 {
890 objc_class_t<A> *super = cls->getSuperclass(cache);
891 if (super) {
892 // Recursively visit superclasses to ensure we have the correct superclass start
893 // Note that we don't need the macho_header, so just pass NULL.
894 visitClass(cache, NULL, super);
895
896 objc_class_data_t<A> *data = cls->getData(cache);
897 objc_class_data_t<A> *super_data = super->getData(cache);
898 int32_t diff = super_data->getInstanceSize() - data->getInstanceStart();
899 if (diff > 0) {
900 IvarWalker<A, IvarOffsetOptimizer<A> > ivarVisitor(*this);
901 maxAlignment = 0;
902 slide = 0;
903
904 // This walk computes maxAlignment
905 ivarVisitor.walk(cache, NULL, cls);
906
907 // Compute a slide value that preserves that alignment
908 uint32_t alignMask = maxAlignment - 1;
909 if (diff & alignMask) diff = (diff + alignMask) & ~alignMask;
910
911 // Slide all of this class's ivars en masse
912 slide = diff;
913 if (slide != 0) {
914 //fprintf(stderr, "Sliding ivars in %s by %u (superclass was %d, now %d)\n", cls->getName(cache), slide, data->getInstanceStart(), super_data->getInstanceSize());
915 ivarVisitor.walk(cache, NULL, cls);
916 data->setInstanceStart(data->getInstanceStart() + slide);
917 data->setInstanceSize(data->getInstanceSize() + slide);
918 }
919 }
920 }
921 }
922
923 // Enumerates objc classes in the module and performs any ivar slides
924 void optimize(SharedCache<A>* cache, const macho_header<P>* header)
925 {
926 // The slide code cannot fix up GC layout strings so skip modules that support ore require GC
927 const macho_section<P> *imageInfoSection = header->getSection("__DATA", "__objc_imageinfo");
928 if (imageInfoSection) {
929 objc_image_info<A> *info = (objc_image_info<A> *)cache->mappedAddressForVMAddress(imageInfoSection->addr());
930 if (!info->supportsGCFlagSet() && !info->requiresGCFlagSet()) {
931 ClassWalker<A, IvarOffsetOptimizer<A> > classVisitor(*this);
932 classVisitor.walk(cache, header);
933 } else {
934 //fprintf(stderr, "GC support present - skipped module\n");
935 }
936 }
937 }
938};
939
940
941// Sort methods in place by selector.
942template <typename A>
943class MethodListSorter {
944
945 typedef typename A::P P;
946 typedef typename A::P::uint_t pint_t;
947
948 uint32_t fOptimized;
949
950 friend class MethodListWalker<A, MethodListSorter<A> >;
951 void visitMethodList(objc_method_list_t<A> *mlist)
952 {
953 typename objc_method_t<A>::SortBySELAddress sorter;
954 std::stable_sort(mlist->begin(), mlist->end(), sorter);
955 mlist->setFixedUp();
956 fOptimized++;
957 }
958
959public:
960 MethodListSorter() : fOptimized(0) { }
961
962 size_t optimized() const { return fOptimized; }
963
964 void optimize(SharedCache<A>* cache, macho_header<P>* header)
965 {
966 MethodListWalker<A, MethodListSorter<A> > mw(*this);
967 mw.walk(cache, header, false /* don't sort protocol method lists*/);
968 }
969};
970
971
972template <typename A>
973class HeaderInfoOptimizer {
974
975 typedef typename A::P P;
976 typedef typename A::P::uint_t pint_t;
977
978 objc_header_info_t<A>* fHinfos;
979 size_t fCount;
980
981public:
982 HeaderInfoOptimizer() : fHinfos(0), fCount(0) { }
983
984 const char *init(size_t count, uint8_t*& buf, size_t& bufSize)
985 {
986 if (count == 0) return NULL;
987
988 if (bufSize < 2*sizeof(uint32_t) + count*sizeof(objc_header_info_t<A>)) {
989 return "libobjc's read/write section is too small (metadata not optimized)";
990 }
991
992 uint32_t *buf32 = (uint32_t *)buf;
993 A::P::E::set32(buf32[0], count);
994 A::P::E::set32(buf32[1], sizeof(objc_header_info_t<A>));
995 fHinfos = (objc_header_info_t<A>*)(buf32+2);
996
997 size_t total = sizeof(uint32_t) + count*sizeof(objc_header_info_t<A>);
998 buf += total;
999 bufSize -= total;
1000
1001 return NULL;
1002 }
1003
1004 void update(SharedCache<A>* cache, const macho_header<P>* mh, std::vector<void*>& pointersInData)
1005 {
1006 objc_header_info_t<A>* hi = new(&fHinfos[fCount++]) objc_header_info_t<A>(cache, mh);
1007 hi->addPointers(pointersInData);
1008 }
1009
1010 objc_header_info_t<A>* hinfoForHeader(SharedCache<A>* cache, const macho_header<P>* mh)
1011 {
1012 // fixme could be binary search
1013 pint_t mh_vmaddr = cache->VMAddressForMappedAddress(mh);
1014 for (size_t i = 0; i < fCount; i++) {
1015 objc_header_info_t<A>* hi = &fHinfos[i];
1016 if (hi->header_vmaddr() == mh_vmaddr) return hi;
1017 }
1018 return NULL;
1019 }
1020};