1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
25 #include "MachOLayout.hpp"
29 // iterate an entsize-based list
30 // typedef entsize_iterator< A, type_t<A>, type_list_t<A> > type_iterator;
31 template <typename A, typename T, typename Tlist>
32 struct entsize_iterator {
34 uint32_t index; // keeping track of this saves a divide in operator-
37 typedef std::random_access_iterator_tag iterator_category;
39 typedef ptrdiff_t difference_type;
43 entsize_iterator() { }
45 entsize_iterator(const Tlist& list, uint32_t start = 0)
46 : entsize(list.getEntsize()), index(start), current(&list.get(start))
49 const entsize_iterator<A,T,Tlist>& operator += (ptrdiff_t count) {
50 current = (T*)((uint8_t *)current + count*entsize);
54 const entsize_iterator<A,T,Tlist>& operator -= (ptrdiff_t count) {
55 current = (T*)((uint8_t *)current - count*entsize);
59 const entsize_iterator<A,T,Tlist> operator + (ptrdiff_t count) const {
60 return entsize_iterator(*this) += count;
62 const entsize_iterator<A,T,Tlist> operator - (ptrdiff_t count) const {
63 return entsize_iterator(*this) -= count;
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;
71 entsize_iterator<A,T,Tlist> operator -- (int) {
72 entsize_iterator<A,T,Tlist> result(*this); *this -= 1; return result;
75 ptrdiff_t operator - (const entsize_iterator<A,T,Tlist>& rhs) const {
76 return (ptrdiff_t)this->index - (ptrdiff_t)rhs.index;
79 T& operator * () { return *current; }
80 T& operator * () const { return *current; }
81 T& operator -> () { return *current; }
82 const T& operator -> () const { return *current; }
84 operator T& () const { return *current; }
86 bool operator == (const entsize_iterator<A,T,Tlist>& rhs) {
87 return this->current == rhs.current;
89 bool operator != (const entsize_iterator<A,T,Tlist>& rhs) {
90 return this->current != rhs.current;
93 bool operator < (const entsize_iterator<A,T,Tlist>& rhs) {
94 return this->current < rhs.current;
96 bool operator > (const entsize_iterator<A,T,Tlist>& rhs) {
97 return this->current > rhs.current;
101 static void overwrite(entsize_iterator<A,T,Tlist>& dst, const Tlist* srcList)
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);
112 template <typename A>
113 class objc_header_info_t {
115 typedef typename A::P P;
116 typedef typename A::P::uint_t pint_t;
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 *
124 bool allClassesRealized;
127 objc_header_info_t(SharedCache<A>* cache, const macho_header<P>* mh)
133 allClassesRealized(0)
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());
139 // can't set fname because dyld sometimes edits it
142 void addPointers(std::vector<void*>& pointersToAdd) {
143 pointersToAdd.push_back(&mhdr);
144 if (info) pointersToAdd.push_back(&info);
147 uint64_t header_vmaddr() const { return mhdr; }
150 template <typename A> class objc_method_list_t; // forward reference
152 template <typename A>
153 class 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>;
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); }
162 struct SortBySELAddress :
163 public std::binary_function<const objc_method_t<A>&,
164 const objc_method_t<A>&, bool>
166 bool operator() (const objc_method_t<A>& lhs,
167 const objc_method_t<A>& rhs)
169 return lhs.getName() < rhs.getName();
174 template <typename A>
175 class objc_method_list_t {
178 objc_method_t<A> first;
180 // use newMethodList instead
181 void* operator new (size_t) { return NULL; }
182 void* operator new (size_t, void* buf) { return buf; }
186 typedef entsize_iterator< A, objc_method_t<A>, objc_method_list_t<A> > method_iterator;
188 uint32_t getCount() const { return A::P::E::get32(count); }
190 uint32_t getEntsize() const {return A::P::E::get32(entsize)&~(uint32_t)3;}
192 objc_method_t<A>& get(uint32_t i) const { return *(objc_method_t<A> *)((uint8_t *)&first + i * getEntsize()); }
194 uint32_t byteSize() const {
195 return byteSizeForCount(getCount(), getEntsize());
198 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_method_t<A>)) {
199 return sizeof(objc_method_list_t<A>) - sizeof(objc_method_t<A>) + c*e;
202 method_iterator begin() { return method_iterator(*this, 0); }
203 method_iterator end() { return method_iterator(*this, getCount()); }
204 const method_iterator begin() const { return method_iterator(*this, 0); }
205 const method_iterator end() const { return method_iterator(*this, getCount()); }
207 void setFixedUp() { A::P::E::set32(entsize, getEntsize() | 3); }
209 void getPointers(std::set<void*>& pointersToRemove) {
210 for(method_iterator it = begin(); it != end(); ++it) {
211 objc_method_t<A>& entry = *it;
212 pointersToRemove.insert(&(entry.name));
213 pointersToRemove.insert(&(entry.types));
214 pointersToRemove.insert(&(entry.imp));
218 static void addPointers(uint8_t* methodList, std::vector<void*>& pointersToAdd) {
219 objc_method_list_t<A>* mlist = (objc_method_list_t<A>*)methodList;
220 for(method_iterator it = mlist->begin(); it != mlist->end(); ++it) {
221 objc_method_t<A>& entry = *it;
222 pointersToAdd.push_back(&(entry.name));
223 pointersToAdd.push_back(&(entry.types));
224 pointersToAdd.push_back(&(entry.imp));
228 static objc_method_list_t<A>* newMethodList(size_t newCount, uint32_t newEntsize) {
229 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
230 return new (buf) objc_method_list_t<A>(newCount, newEntsize);
233 void operator delete(void * p) {
237 objc_method_list_t(uint32_t newCount,
238 uint32_t newEntsize = sizeof(objc_method_t<A>))
239 : entsize(newEntsize), count(newCount)
243 template <typename A>
245 typedef typename A::P::uint_t pint_t;
246 typename A::P::uint_t offset; // A::P *
247 typename A::P::uint_t name; // const char *
248 typename A::P::uint_t type; // const char *
253 const char * getName(SharedCache<A> *cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
255 bool hasOffset() const { return A::P::getP(offset) != 0; }
256 pint_t getOffset(SharedCache<A> *cache) const { return A::P::getP(*(pint_t * const)cache->mappedAddressForVMAddress(A::P::getP(offset))); }
257 void setOffset(SharedCache<A> *cache, pint_t newOffset) { A::P::setP(*(pint_t *)cache->mappedAddressForVMAddress(A::P::getP(offset)), newOffset); }
259 uint32_t getAlignment()
261 uint32_t a = A::P::E::get32(alignment);
262 return a == (uint32_t)-1 ? sizeof(typename A::P::uint_t) : 1<<a;
266 template <typename A>
267 class objc_ivar_list_t {
268 typedef typename A::P::uint_t pint_t;
271 objc_ivar_t<A> first;
273 // use newIvarList instead
274 void* operator new (size_t) { return NULL; }
275 void* operator new (size_t, void* buf) { return buf; }
279 typedef entsize_iterator< A, objc_ivar_t<A>, objc_ivar_list_t<A> > ivar_iterator;
281 uint32_t getCount() const { return A::P::E::get32(count); }
283 uint32_t getEntsize() const { return A::P::E::get32(entsize); }
285 objc_ivar_t<A>& get(pint_t i) const { return *(objc_ivar_t<A> *)((uint8_t *)&first + i * A::P::E::get32(entsize)); }
287 uint32_t byteSize() const {
288 return byteSizeForCount(getCount(), getEntsize());
291 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_ivar_t<A>)) {
292 return sizeof(objc_ivar_list_t<A>) - sizeof(objc_ivar_t<A>) + c*e;
295 ivar_iterator begin() { return ivar_iterator(*this, 0); }
296 ivar_iterator end() { return ivar_iterator(*this, getCount()); }
297 const ivar_iterator begin() const { return ivar_iterator(*this, 0); }
298 const ivar_iterator end() const { return ivar_iterator(*this, getCount()); }
300 static objc_ivar_list_t<A>* newIvarList(size_t newCount, uint32_t newEntsize) {
301 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
302 return new (buf) objc_ivar_list_t<A>(newCount, newEntsize);
305 void operator delete(void * p) {
309 objc_ivar_list_t(uint32_t newCount,
310 uint32_t newEntsize = sizeof(objc_ivar_t<A>))
311 : entsize(newEntsize), count(newCount)
317 template <typename A> class objc_property_list_t; // forward
319 template <typename A>
320 class objc_property_t {
321 typename A::P::uint_t name;
322 typename A::P::uint_t attributes;
323 friend class objc_property_list_t<A>;
326 const char * getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
328 const char * getAttributes(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(attributes)); }
331 template <typename A>
332 class objc_property_list_t {
335 objc_property_t<A> first;
337 // use newPropertyList instead
338 void* operator new (size_t) { return NULL; }
339 void* operator new (size_t, void* buf) { return buf; }
343 typedef entsize_iterator< A, objc_property_t<A>, objc_property_list_t<A> > property_iterator;
345 uint32_t getCount() const { return A::P::E::get32(count); }
347 uint32_t getEntsize() const { return A::P::E::get32(entsize); }
349 objc_property_t<A>& get(uint32_t i) const { return *(objc_property_t<A> *)((uint8_t *)&first + i * getEntsize()); }
351 uint32_t byteSize() const {
352 return byteSizeForCount(getCount(), getEntsize());
355 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_property_t<A>)) {
356 return sizeof(objc_property_list_t<A>) - sizeof(objc_property_t<A>) + c*e;
359 property_iterator begin() { return property_iterator(*this, 0); }
360 property_iterator end() { return property_iterator(*this, getCount()); }
361 const property_iterator begin() const { return property_iterator(*this, 0); }
362 const property_iterator end() const { return property_iterator(*this, getCount()); }
364 void getPointers(std::set<void*>& pointersToRemove) {
365 for(property_iterator it = begin(); it != end(); ++it) {
366 objc_property_t<A>& entry = *it;
367 pointersToRemove.insert(&(entry.name));
368 pointersToRemove.insert(&(entry.attributes));
372 static void addPointers(uint8_t* propertyList, std::vector<void*>& pointersToAdd) {
373 objc_property_list_t<A>* plist = (objc_property_list_t<A>*)propertyList;
374 for(property_iterator it = plist->begin(); it != plist->end(); ++it) {
375 objc_property_t<A>& entry = *it;
376 pointersToAdd.push_back(&(entry.name));
377 pointersToAdd.push_back(&(entry.attributes));
381 static objc_property_list_t<A>* newPropertyList(size_t newCount, uint32_t newEntsize) {
382 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
383 return new (buf) objc_property_list_t<A>(newCount, newEntsize);
386 void operator delete(void * p) {
390 objc_property_list_t(uint32_t newCount,
391 uint32_t newEntsize = sizeof(objc_property_t<A>))
392 : entsize(newEntsize), count(newCount)
397 template <typename A>
398 class objc_protocol_t {
399 typename A::P::uint_t isa;
400 typename A::P::uint_t name;
401 typename A::P::uint_t protocols;
402 typename A::P::uint_t instanceMethods;
403 typename A::P::uint_t classMethods;
404 typename A::P::uint_t optionalInstanceMethods;
405 typename A::P::uint_t optionalClassMethods;
406 typename A::P::uint_t instanceProperties;
409 objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceMethods)); }
411 objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(classMethods)); }
413 objc_method_list_t<A> *getOptionalInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(optionalInstanceMethods)); }
415 objc_method_list_t<A> *getOptionalClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(optionalClassMethods)); }
419 template <typename A>
420 class objc_protocol_list_t {
421 typedef typename A::P::uint_t pint_t;
425 // use newProtocolList instead
426 void* operator new (size_t) { return NULL; }
427 void* operator new (size_t, void* buf) { return buf; }
431 pint_t getCount() const { return A::P::getP(count); }
433 objc_protocol_t<A>* get(SharedCache<A>* cache, pint_t i) {
434 return (objc_protocol_t<A>*)cache->mappedAddressForVMAddress(A::P::getP(list[i]));
437 void overwrite(pint_t& index, const objc_protocol_list_t<A>* src) {
438 pint_t srcCount = src->getCount();
439 memcpy(list+index, src->list, srcCount * sizeof(pint_t));
443 uint32_t byteSize() const {
444 return byteSizeForCount(getCount());
446 static uint32_t byteSizeForCount(pint_t c) {
447 return sizeof(objc_protocol_list_t<A>) + c*sizeof(pint_t);
450 void getPointers(std::set<void*>& pointersToRemove) {
451 for(int i=0 ; i < count; ++i) {
452 pointersToRemove.insert(&list[i]);
456 static void addPointers(uint8_t* protocolList, std::vector<void*>& pointersToAdd) {
457 objc_protocol_list_t<A>* plist = (objc_protocol_list_t<A>*)protocolList;
458 for(int i=0 ; i < plist->count; ++i) {
459 pointersToAdd.push_back(&plist->list[i]);
463 static objc_protocol_list_t<A>* newProtocolList(pint_t newCount) {
464 void *buf = ::calloc(byteSizeForCount(newCount), 1);
465 return new (buf) objc_protocol_list_t<A>(newCount);
468 void operator delete(void * p) {
472 objc_protocol_list_t(uint32_t newCount) : count(newCount) { }
477 template <typename A>
478 class objc_class_data_t {
480 uint32_t instanceStart;
481 // Note there is 4-bytes of alignment padding between instanceSize and ivarLayout
482 // on 64-bit archs, but no padding on 32-bit archs.
483 // This union is a way to model that.
485 uint32_t instanceSize;
486 typename A::P::uint_t pad;
488 typename A::P::uint_t ivarLayout;
489 typename A::P::uint_t name;
490 typename A::P::uint_t baseMethods;
491 typename A::P::uint_t baseProtocols;
492 typename A::P::uint_t ivars;
493 typename A::P::uint_t weakIvarLayout;
494 typename A::P::uint_t baseProperties;
497 bool isMetaClass() { return A::P::E::get32(flags) & 1; }
499 uint32_t getInstanceStart() { return A::P::E::get32(instanceStart); }
500 void setInstanceStart(uint32_t newStart) { A::P::E::set32(instanceStart, newStart); }
502 uint32_t getInstanceSize() { return A::P::E::get32(instanceSize.instanceSize); }
503 void setInstanceSize(uint32_t newSiz) { A::P::E::set32(instanceSize.instanceSize, newSiz); }
505 objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseMethods)); }
507 objc_protocol_list_t<A> *getProtocolList(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProtocols)); }
509 objc_ivar_list_t<A> *getIvarList(SharedCache<A>* cache) const { return (objc_ivar_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(ivars)); }
511 objc_property_list_t<A> *getPropertyList(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProperties)); }
513 const char * getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
515 void setMethodList(SharedCache<A>* cache, objc_method_list_t<A>* mlist) {
516 A::P::setP(baseMethods, cache->VMAddressForMappedAddress(mlist));
519 void setProtocolList(SharedCache<A>* cache, objc_protocol_list_t<A>* protolist) {
520 A::P::setP(baseProtocols, cache->VMAddressForMappedAddress(protolist));
523 void setPropertyList(SharedCache<A>* cache, objc_property_list_t<A>* proplist) {
524 A::P::setP(baseProperties, cache->VMAddressForMappedAddress(proplist));
527 void addMethodListPointer(std::vector<void*>& pointersToAdd) {
528 pointersToAdd.push_back(&this->baseMethods);
531 void addPropertyListPointer(std::vector<void*>& pointersToAdd) {
532 pointersToAdd.push_back(&this->baseProperties);
535 void addProtocolListPointer(std::vector<void*>& pointersToAdd) {
536 pointersToAdd.push_back(&this->baseProtocols);
540 template <typename A>
542 typename A::P::uint_t isa;
543 typename A::P::uint_t superclass;
544 typename A::P::uint_t method_cache;
545 typename A::P::uint_t vtable;
546 typename A::P::uint_t data;
549 bool isMetaClass(SharedCache<A>* cache) const { return getData(cache)->isMetaClass(); }
551 objc_class_t<A> *getIsa(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(isa)); }
553 objc_class_t<A> *getSuperclass(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(superclass)); }
555 objc_class_data_t<A> *getData(SharedCache<A>* cache) const { return (objc_class_data_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(data)); }
557 objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return getData(cache)->getMethodList(cache); }
559 objc_protocol_list_t<A> *getProtocolList(SharedCache<A>* cache) const { return getData(cache)->getProtocolList(cache); }
561 objc_property_list_t<A> *getPropertyList(SharedCache<A>* cache) const { return getData(cache)->getPropertyList(cache); }
563 const char * getName(SharedCache<A>* cache) const {
564 return getData(cache)->getName(cache);
567 void setMethodList(SharedCache<A>* cache, objc_method_list_t<A>* mlist) {
568 getData(cache)->setMethodList(cache, mlist);
571 void setProtocolList(SharedCache<A>* cache, objc_protocol_list_t<A>* protolist) {
572 getData(cache)->setProtocolList(cache, protolist);
575 void setPropertyList(SharedCache<A>* cache, objc_property_list_t<A>* proplist) {
576 getData(cache)->setPropertyList(cache, proplist);
579 void addMethodListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
580 getData(cache)->addMethodListPointer(pointersToAdd);
583 void addPropertyListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
584 getData(cache)->addPropertyListPointer(pointersToAdd);
587 void addProtocolListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
588 getData(cache)->addProtocolListPointer(pointersToAdd);
595 template <typename A>
596 class objc_category_t {
597 typename A::P::uint_t name;
598 typename A::P::uint_t cls;
599 typename A::P::uint_t instanceMethods;
600 typename A::P::uint_t classMethods;
601 typename A::P::uint_t protocols;
602 typename A::P::uint_t instanceProperties;
606 const char * getName(SharedCache<A> *cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
608 objc_class_t<A> *getClass(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(cls)); }
610 objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceMethods)); }
612 objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(classMethods)); }
614 objc_protocol_list_t<A> *getProtocols(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(protocols)); }
616 objc_property_list_t<A> *getInstanceProperties(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceProperties)); }
618 void getPointers(std::set<void*>& pointersToRemove) {
619 pointersToRemove.insert(&name);
620 pointersToRemove.insert(&cls);
621 pointersToRemove.insert(&instanceMethods);
622 pointersToRemove.insert(&classMethods);
623 pointersToRemove.insert(&protocols);
624 pointersToRemove.insert(&instanceProperties);
630 template <typename A>
631 class objc_message_ref_t {
632 typename A::P::uint_t imp;
633 typename A::P::uint_t sel;
636 typename A::P::uint_t getName() const { return A::P::getP(sel); }
638 void setName(typename A::P::uint_t newName) { A::P::setP(sel, newName); }
641 // Call visitor.visitIvar() on every ivar in a given class.
642 template <typename A, typename V>
644 typedef typename A::P P;
645 typedef typename A::P::uint_t pint_t;
649 IvarWalker(V& visitor) : ivarVisitor(visitor) { }
651 void walk(SharedCache<A>* cache, const macho_header<P>* header, objc_class_t<A> *cls)
653 objc_class_data_t<A> *data = cls->getData(cache);
654 objc_ivar_list_t<A> *ivars = data->getIvarList(cache);
656 for (pint_t i = 0; i < ivars->getCount(); i++) {
657 objc_ivar_t<A>& ivar = ivars->get(i);
658 //fprintf(stderr, "visiting ivar: %s\n", ivar.getName(cache));
659 ivarVisitor.visitIvar(cache, header, cls, &ivar);
662 //fprintf(stderr, "no ivars\n");
666 void visitClass(SharedCache<A>* cache, const macho_header<P>* header, objc_class_t<A> *cls)
668 walk(cache, header, cls);
672 // Call visitor.visitClass() on every class.
673 template <typename A, typename V>
675 typedef typename A::P P;
676 typedef typename A::P::uint_t pint_t;
680 ClassWalker(V& visitor) : classVisitor(visitor) { }
682 void walk(SharedCache<A>* cache, const macho_header<P>* header)
684 PointerSection<A, objc_class_t<A> *>
685 classes(cache, header, "__DATA", "__objc_classlist");
687 for (pint_t i = 0; i < classes.count(); i++) {
688 objc_class_t<A> *cls = classes.get(i);
689 //fprintf(stderr, "visiting class: %s\n", cls->getName(cache));
690 classVisitor.visitClass(cache, header, cls);
696 // Call visitor.visitMethodList(mlist) on every method list in a header.
697 template <typename A, typename V>
698 class MethodListWalker {
700 typedef typename A::P P;
701 typedef typename A::P::uint_t pint_t;
707 MethodListWalker(V& visitor) : mVisitor(visitor) { }
709 void walk(SharedCache<A>* cache, const macho_header<P>* header, bool walkProtocols)
711 // Method lists in classes
712 PointerSection<A, objc_class_t<A> *>
713 classes(cache, header, "__DATA", "__objc_classlist");
715 for (pint_t i = 0; i < classes.count(); i++) {
716 objc_class_t<A> *cls = classes.get(i);
717 objc_method_list_t<A> *mlist;
718 if ((mlist = cls->getMethodList(cache))) {
719 mVisitor.visitMethodList(mlist);
721 if ((mlist = cls->getIsa(cache)->getMethodList(cache))) {
722 mVisitor.visitMethodList(mlist);
726 // Method lists from categories
727 PointerSection<A, objc_category_t<A> *>
728 cats(cache, header, "__DATA", "__objc_catlist");
729 for (pint_t i = 0; i < cats.count(); i++) {
730 objc_category_t<A> *cat = cats.get(i);
731 objc_method_list_t<A> *mlist;
732 if ((mlist = cat->getInstanceMethods(cache))) {
733 mVisitor.visitMethodList(mlist);
735 if ((mlist = cat->getClassMethods(cache))) {
736 mVisitor.visitMethodList(mlist);
740 // Method description lists from protocols
741 if ( walkProtocols ) {
742 PointerSection<A, objc_protocol_t<A> *>
743 protocols(cache, header, "__DATA", "__objc_protolist");
744 for (pint_t i = 0; i < protocols.count(); i++) {
745 objc_protocol_t<A> *proto = protocols.get(i);
746 objc_method_list_t<A> *mlist;
747 if ((mlist = proto->getInstanceMethods(cache))) {
748 mVisitor.visitMethodList(mlist);
750 if ((mlist = proto->getClassMethods(cache))) {
751 mVisitor.visitMethodList(mlist);
753 if ((mlist = proto->getOptionalInstanceMethods(cache))) {
754 mVisitor.visitMethodList(mlist);
756 if ((mlist = proto->getOptionalClassMethods(cache))) {
757 mVisitor.visitMethodList(mlist);
765 // Update selector references. The visitor performs recording and uniquing.
766 template <typename A, typename V>
767 class SelectorOptimizer {
769 typedef typename A::P P;
770 typedef typename A::P::uint_t pint_t;
774 friend class MethodListWalker< A, SelectorOptimizer<A,V> >;
775 void visitMethodList(objc_method_list_t<A> *mlist)
777 // Gather selectors. Update method names.
778 for (pint_t m = 0; m < mlist->getCount(); m++) {
779 pint_t oldValue = mlist->get(m).getName();
780 pint_t newValue = mVisitor.visit(oldValue);
781 mlist->get(m).setName(newValue);
783 // Do not setFixedUp: the methods are not yet sorted.
788 SelectorOptimizer(V& visitor) : mVisitor(visitor) { }
790 void optimize(SharedCache<A>* cache, const macho_header<P>* header)
792 // method lists of all kinds
793 MethodListWalker< A, SelectorOptimizer<A,V> > mw(*this);
794 mw.walk(cache, header, true);
796 // @selector references
797 PointerSection<A, const char *>
798 selrefs(cache, header, "__DATA", "__objc_selrefs");
799 for (pint_t i = 0; i < selrefs.count(); i++) {
800 pint_t oldValue = selrefs.getUnmapped(i);
801 pint_t newValue = mVisitor.visit(oldValue);
802 selrefs.set(i, newValue);
805 // message references
806 ArraySection<A, objc_message_ref_t<A> >
807 msgrefs(cache, header, "__DATA", "__objc_msgrefs");
808 for (pint_t i = 0; i < msgrefs.count(); i++) {
809 objc_message_ref_t<A>& msg = msgrefs.get(i);
810 pint_t oldValue = msg.getName();
811 pint_t newValue = mVisitor.visit(oldValue);
812 msg.setName(newValue);
818 // Update selector references. The visitor performs recording and uniquing.
819 template <typename A>
820 class IvarOffsetOptimizer {
821 typedef typename A::P P;
824 uint32_t maxAlignment;
830 IvarOffsetOptimizer() : fOptimized(0) { }
832 size_t optimized() const { return fOptimized; }
834 // dual purpose ivar visitor function
835 // if slide!=0 then slides the ivar by that amount, otherwise computes maxAlignment
836 void visitIvar(SharedCache<A>* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<A> *cls, objc_ivar_t<A> *ivar)
839 uint32_t alignment = ivar->getAlignment();
840 if (alignment > maxAlignment) maxAlignment = alignment;
842 // skip anonymous bitfields
843 if (ivar->hasOffset()) {
844 uint32_t oldOffset = (uint32_t)ivar->getOffset(cache);
845 ivar->setOffset(cache, oldOffset + slide);
847 //fprintf(stderr, "%d -> %d for %s.%s\n", oldOffset, oldOffset + slide, cls->getName(cache), ivar->getName(cache));
849 //fprintf(stderr, "NULL offset\n");
854 // Class visitor function. Evaluates whether to slide ivars and performs slide if needed.
855 // The slide algorithm is also implemented in objc. Any changes here should be reflected there also.
856 void visitClass(SharedCache<A>* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<A> *cls)
858 objc_class_t<A> *super = cls->getSuperclass(cache);
860 // Recursively visit superclasses to ensure we have the correct superclass start
861 // Note that we don't need the macho_header, so just pass NULL.
862 visitClass(cache, NULL, super);
864 objc_class_data_t<A> *data = cls->getData(cache);
865 objc_class_data_t<A> *super_data = super->getData(cache);
866 int32_t diff = super_data->getInstanceSize() - data->getInstanceStart();
868 IvarWalker<A, IvarOffsetOptimizer<A> > ivarVisitor(*this);
872 // This walk computes maxAlignment
873 ivarVisitor.walk(cache, NULL, cls);
875 // Compute a slide value that preserves that alignment
876 uint32_t alignMask = maxAlignment - 1;
877 if (diff & alignMask) diff = (diff + alignMask) & ~alignMask;
879 // Slide all of this class's ivars en masse
882 //fprintf(stderr, "Sliding ivars in %s by %u (superclass was %d, now %d)\n", cls->getName(cache), slide, data->getInstanceStart(), super_data->getInstanceSize());
883 ivarVisitor.walk(cache, NULL, cls);
884 data->setInstanceStart(data->getInstanceStart() + slide);
885 data->setInstanceSize(data->getInstanceSize() + slide);
891 // Enumerates objc classes in the module and performs any ivar slides
892 void optimize(SharedCache<A>* cache, const macho_header<P>* header)
894 // The slide code cannot fix up GC layout strings so skip modules that support ore require GC
895 const macho_section<P> *imageInfoSection = header->getSection("__DATA", "__objc_imageinfo");
896 if (imageInfoSection) {
897 objc_image_info<A> *info = (objc_image_info<A> *)cache->mappedAddressForVMAddress(imageInfoSection->addr());
898 if (!info->supportsGCFlagSet() && !info->requiresGCFlagSet()) {
899 ClassWalker<A, IvarOffsetOptimizer<A> > classVisitor(*this);
900 classVisitor.walk(cache, header);
902 //fprintf(stderr, "GC support present - skipped module\n");
909 // Sort methods in place by selector.
910 template <typename A>
911 class MethodListSorter {
913 typedef typename A::P P;
914 typedef typename A::P::uint_t pint_t;
918 friend class MethodListWalker<A, MethodListSorter<A> >;
919 void visitMethodList(objc_method_list_t<A> *mlist)
921 typename objc_method_t<A>::SortBySELAddress sorter;
922 std::stable_sort(mlist->begin(), mlist->end(), sorter);
928 MethodListSorter() : fOptimized(0) { }
930 size_t optimized() const { return fOptimized; }
932 void optimize(SharedCache<A>* cache, macho_header<P>* header)
934 MethodListWalker<A, MethodListSorter<A> > mw(*this);
935 mw.walk(cache, header, false /* don't sort protocol method lists*/);
940 template <typename A>
941 class HeaderInfoOptimizer {
943 typedef typename A::P P;
944 typedef typename A::P::uint_t pint_t;
946 objc_header_info_t<A>* fHinfos;
950 HeaderInfoOptimizer() : fHinfos(0), fCount(0) { }
952 const char *init(size_t count, uint8_t*& buf, size_t& bufSize)
954 if (count == 0) return NULL;
956 if (bufSize < 2*sizeof(uint32_t) + count*sizeof(objc_header_info_t<A>)) {
957 return "libobjc's read/write section is too small (metadata not optimized)";
960 uint32_t *buf32 = (uint32_t *)buf;
961 A::P::E::set32(buf32[0], count);
962 A::P::E::set32(buf32[1], sizeof(objc_header_info_t<A>));
963 fHinfos = (objc_header_info_t<A>*)(buf32+2);
965 size_t total = sizeof(uint32_t) + count*sizeof(objc_header_info_t<A>);
972 void update(SharedCache<A>* cache, const macho_header<P>* mh, std::vector<void*>& pointersInData)
974 objc_header_info_t<A>* hi = new(&fHinfos[fCount++]) objc_header_info_t<A>(cache, mh);
975 hi->addPointers(pointersInData);
978 objc_header_info_t<A>* hinfoForHeader(SharedCache<A>* cache, const macho_header<P>* mh)
980 // fixme could be binary search
981 pint_t mh_vmaddr = cache->VMAddressForMappedAddress(mh);
982 for (size_t i = 0; i < fCount; i++) {
983 objc_header_info_t<A>* hi = &fHinfos[i];
984 if (hi->header_vmaddr() == mh_vmaddr) return hi;