]> git.saurik.com Git - apple/dyld.git/blame - launch-cache/ObjCModernAbstraction.hpp
dyld-360.21.tar.gz
[apple/dyld.git] / launch-cache / ObjCModernAbstraction.hpp
CommitLineData
39a8cd10
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
412ebb8e 3 * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
39a8cd10
A
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
832b6fce 25#include "MachOLayout.hpp"
412ebb8e
A
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; }
832b6fce 80 T& operator * () const { return *current; }
412ebb8e
A
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 }
412ebb8e 99};
832b6fce
A
100
101template <typename A>
102class objc_header_info_t {
103
104 typedef typename A::P P;
105 typedef typename A::P::uint_t pint_t;
106
107 pint_t next; // objc_header_info *
108 pint_t mhdr; // mach_header or mach_header_64
109 pint_t info; // objc_image_info *
110 pint_t fname; // const char *
111 bool loaded;
112 bool inSharedCache;
113 bool allClassesRealized;
114
115public:
116 objc_header_info_t(SharedCache<A>* cache, const macho_header<P>* mh)
117 : next(0),
118 mhdr(0),
119 info(0),
120 fname(0),
121 loaded(0),
122 allClassesRealized(0)
123 {
124 A::P::setP(mhdr, cache->VMAddressForMappedAddress(mh));
125 const macho_section<P>* sect = mh->getSection("__DATA", "__objc_imageinfo");
126 if (sect) A::P::setP(info, sect->addr());
127
128 // can't set fname because dyld sometimes edits it
129 }
130
131 void addPointers(std::vector<void*>& pointersToAdd) {
132 pointersToAdd.push_back(&mhdr);
133 if (info) pointersToAdd.push_back(&info);
134 }
135
136 uint64_t header_vmaddr() const { return mhdr; }
137};
412ebb8e
A
138
139template <typename A> class objc_method_list_t; // forward reference
140
39a8cd10
A
141template <typename A>
142class objc_method_t {
143 typename A::P::uint_t name; // SEL
144 typename A::P::uint_t types; // const char *
145 typename A::P::uint_t imp; // IMP
412ebb8e 146 friend class objc_method_list_t<A>;
39a8cd10
A
147public:
148 typename A::P::uint_t getName() const { return A::P::getP(name); }
149 void setName(typename A::P::uint_t newName) { A::P::setP(name, newName); }
412ebb8e
A
150
151 struct SortBySELAddress :
152 public std::binary_function<const objc_method_t<A>&,
153 const objc_method_t<A>&, bool>
154 {
155 bool operator() (const objc_method_t<A>& lhs,
156 const objc_method_t<A>& rhs)
157 {
158 return lhs.getName() < rhs.getName();
159 }
160 };
39a8cd10
A
161};
162
163template <typename A>
164class objc_method_list_t {
165 uint32_t entsize;
166 uint32_t count;
167 objc_method_t<A> first;
168
412ebb8e 169 void* operator new (size_t, void* buf) { return buf; }
39a8cd10
A
170
171public:
39a8cd10 172
412ebb8e
A
173 typedef entsize_iterator< A, objc_method_t<A>, objc_method_list_t<A> > method_iterator;
174
175 uint32_t getCount() const { return A::P::E::get32(count); }
176
177 uint32_t getEntsize() const {return A::P::E::get32(entsize)&~(uint32_t)3;}
178
179 objc_method_t<A>& get(uint32_t i) const { return *(objc_method_t<A> *)((uint8_t *)&first + i * getEntsize()); }
180
181 uint32_t byteSize() const {
182 return byteSizeForCount(getCount(), getEntsize());
183 }
184
185 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_method_t<A>)) {
186 return sizeof(objc_method_list_t<A>) - sizeof(objc_method_t<A>) + c*e;
187 }
188
189 method_iterator begin() { return method_iterator(*this, 0); }
190 method_iterator end() { return method_iterator(*this, getCount()); }
191 const method_iterator begin() const { return method_iterator(*this, 0); }
192 const method_iterator end() const { return method_iterator(*this, getCount()); }
39a8cd10
A
193
194 void setFixedUp() { A::P::E::set32(entsize, getEntsize() | 3); }
412ebb8e
A
195
196 void getPointers(std::set<void*>& pointersToRemove) {
197 for(method_iterator it = begin(); it != end(); ++it) {
198 objc_method_t<A>& entry = *it;
199 pointersToRemove.insert(&(entry.name));
200 pointersToRemove.insert(&(entry.types));
201 pointersToRemove.insert(&(entry.imp));
202 }
203 }
204
205 static void addPointers(uint8_t* methodList, std::vector<void*>& pointersToAdd) {
206 objc_method_list_t<A>* mlist = (objc_method_list_t<A>*)methodList;
207 for(method_iterator it = mlist->begin(); it != mlist->end(); ++it) {
208 objc_method_t<A>& entry = *it;
209 pointersToAdd.push_back(&(entry.name));
210 pointersToAdd.push_back(&(entry.types));
211 pointersToAdd.push_back(&(entry.imp));
212 }
213 }
214
215 static objc_method_list_t<A>* newMethodList(size_t newCount, uint32_t newEntsize) {
216 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
217 return new (buf) objc_method_list_t<A>(newCount, newEntsize);
218 }
219
220 void operator delete(void * p) {
221 ::free(p);
222 }
223
224 objc_method_list_t(uint32_t newCount,
225 uint32_t newEntsize = sizeof(objc_method_t<A>))
226 : entsize(newEntsize), count(newCount)
227 { }
19894a12
A
228
229private:
230 // use newMethodList instead
231 void* operator new (size_t);
232};
233
234
235// Ivar offset variables are 64-bit on x86_64 and 32-bit everywhere else.
236
237template <typename A>
238class objc_ivar_offset_t {
239 typedef typename A::P::uint_t pint_t;
240 typename A::P::uint_t ptr; // uint32_t *
241
242 uint32_t& offset(SharedCache<A> *cache) const { return *(uint32_t *)cache->mappedAddressForVMAddress(A::P::getP(ptr)); }
243
244public:
245 bool hasOffset() const { return A::P::getP(ptr) != 0; }
246 pint_t getOffset(SharedCache<A> *cache) const { return A::P::E::get32(offset(cache)); }
247 void setOffset(SharedCache<A> *cache, pint_t newOffset) { A::P::E::set32(offset(cache), newOffset); }
248};
249
250template <>
251class objc_ivar_offset_t<x86_64> {
252 typedef x86_64 A;
253 typedef typename A::P::uint_t pint_t;
254 typename A::P::uint_t ptr; // uint64_t *
255
256 uint64_t& offset(SharedCache<A> *cache) const { return *(uint64_t *)cache->mappedAddressForVMAddress(A::P::getP(ptr)); }
257
258public:
259 bool hasOffset() const { return A::P::getP(ptr) != 0; }
260 pint_t getOffset(SharedCache<A> *cache) const { return A::P::E::get64(offset(cache)); }
261 void setOffset(SharedCache<A> *cache, pint_t newOffset) { A::P::E::set64(offset(cache), newOffset); }
39a8cd10
A
262};
263
264template <typename A>
265class objc_ivar_t {
832b6fce 266 typedef typename A::P::uint_t pint_t;
19894a12 267 objc_ivar_offset_t<A> offset; // uint32_t * (uint64_t * on x86_64)
39a8cd10
A
268 typename A::P::uint_t name; // const char *
269 typename A::P::uint_t type; // const char *
270 uint32_t alignment;
271 uint32_t size;
832b6fce
A
272
273public:
274 const char * getName(SharedCache<A> *cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
275
19894a12
A
276 bool hasOffset() const { return offset.hasOffset(); }
277 pint_t getOffset(SharedCache<A> *cache) const { return offset.getOffset(cache); }
278 void setOffset(SharedCache<A> *cache, pint_t newOffset) { offset.setOffset(cache, newOffset); }
832b6fce
A
279
280 uint32_t getAlignment()
281 {
282 uint32_t a = A::P::E::get32(alignment);
283 return a == (uint32_t)-1 ? sizeof(typename A::P::uint_t) : 1<<a;
284 }
39a8cd10
A
285};
286
287template <typename A>
288class objc_ivar_list_t {
832b6fce 289 typedef typename A::P::uint_t pint_t;
39a8cd10
A
290 uint32_t entsize;
291 uint32_t count;
292 objc_ivar_t<A> first;
293
412ebb8e
A
294 void* operator new (size_t, void* buf) { return buf; }
295
296public:
297
298 typedef entsize_iterator< A, objc_ivar_t<A>, objc_ivar_list_t<A> > ivar_iterator;
299
300 uint32_t getCount() const { return A::P::E::get32(count); }
301
302 uint32_t getEntsize() const { return A::P::E::get32(entsize); }
303
832b6fce 304 objc_ivar_t<A>& get(pint_t i) const { return *(objc_ivar_t<A> *)((uint8_t *)&first + i * A::P::E::get32(entsize)); }
412ebb8e
A
305
306 uint32_t byteSize() const {
307 return byteSizeForCount(getCount(), getEntsize());
308 }
309
310 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_ivar_t<A>)) {
311 return sizeof(objc_ivar_list_t<A>) - sizeof(objc_ivar_t<A>) + c*e;
312 }
313
314 ivar_iterator begin() { return ivar_iterator(*this, 0); }
315 ivar_iterator end() { return ivar_iterator(*this, getCount()); }
316 const ivar_iterator begin() const { return ivar_iterator(*this, 0); }
317 const ivar_iterator end() const { return ivar_iterator(*this, getCount()); }
318
319 static objc_ivar_list_t<A>* newIvarList(size_t newCount, uint32_t newEntsize) {
320 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
321 return new (buf) objc_ivar_list_t<A>(newCount, newEntsize);
322 }
323
324 void operator delete(void * p) {
325 ::free(p);
326 }
327
328 objc_ivar_list_t(uint32_t newCount,
329 uint32_t newEntsize = sizeof(objc_ivar_t<A>))
330 : entsize(newEntsize), count(newCount)
331 { }
19894a12
A
332private:
333 // use newIvarList instead
334 void* operator new (size_t);
412ebb8e
A
335};
336
337
338template <typename A> class objc_property_list_t; // forward
339
340template <typename A>
341class objc_property_t {
342 typename A::P::uint_t name;
343 typename A::P::uint_t attributes;
344 friend class objc_property_list_t<A>;
39a8cd10 345public:
412ebb8e
A
346
347 const char * getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
348
349 const char * getAttributes(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(attributes)); }
350};
351
352template <typename A>
353class objc_property_list_t {
354 uint32_t entsize;
355 uint32_t count;
356 objc_property_t<A> first;
357
412ebb8e
A
358 void* operator new (size_t, void* buf) { return buf; }
359
360public:
361
362 typedef entsize_iterator< A, objc_property_t<A>, objc_property_list_t<A> > property_iterator;
363
364 uint32_t getCount() const { return A::P::E::get32(count); }
365
366 uint32_t getEntsize() const { return A::P::E::get32(entsize); }
367
368 objc_property_t<A>& get(uint32_t i) const { return *(objc_property_t<A> *)((uint8_t *)&first + i * getEntsize()); }
369
370 uint32_t byteSize() const {
371 return byteSizeForCount(getCount(), getEntsize());
372 }
373
374 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_property_t<A>)) {
375 return sizeof(objc_property_list_t<A>) - sizeof(objc_property_t<A>) + c*e;
376 }
377
378 property_iterator begin() { return property_iterator(*this, 0); }
379 property_iterator end() { return property_iterator(*this, getCount()); }
380 const property_iterator begin() const { return property_iterator(*this, 0); }
381 const property_iterator end() const { return property_iterator(*this, getCount()); }
382
383 void getPointers(std::set<void*>& pointersToRemove) {
384 for(property_iterator it = begin(); it != end(); ++it) {
385 objc_property_t<A>& entry = *it;
386 pointersToRemove.insert(&(entry.name));
387 pointersToRemove.insert(&(entry.attributes));
388 }
389 }
390
391 static void addPointers(uint8_t* propertyList, std::vector<void*>& pointersToAdd) {
392 objc_property_list_t<A>* plist = (objc_property_list_t<A>*)propertyList;
393 for(property_iterator it = plist->begin(); it != plist->end(); ++it) {
394 objc_property_t<A>& entry = *it;
395 pointersToAdd.push_back(&(entry.name));
396 pointersToAdd.push_back(&(entry.attributes));
397 }
398 }
399
400 static objc_property_list_t<A>* newPropertyList(size_t newCount, uint32_t newEntsize) {
401 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
402 return new (buf) objc_property_list_t<A>(newCount, newEntsize);
403 }
404
405 void operator delete(void * p) {
406 ::free(p);
407 }
408
409 objc_property_list_t(uint32_t newCount,
410 uint32_t newEntsize = sizeof(objc_property_t<A>))
411 : entsize(newEntsize), count(newCount)
412 { }
19894a12
A
413private:
414 // use newPropertyList instead
415 void* operator new (size_t);
39a8cd10
A
416};
417
df9d6cf7
A
418
419template <typename A> class objc_protocol_list_t; // forward reference
420
39a8cd10
A
421template <typename A>
422class objc_protocol_t {
df9d6cf7
A
423 typedef typename A::P::uint_t pint_t;
424
425 pint_t isa;
426 pint_t name;
427 pint_t protocols;
428 pint_t instanceMethods;
429 pint_t classMethods;
430 pint_t optionalInstanceMethods;
431 pint_t optionalClassMethods;
432 pint_t instanceProperties;
433 uint32_t size;
434 uint32_t flags;
435 pint_t extendedMethodTypes;
436 pint_t demangledName;
39a8cd10
A
437
438public:
df9d6cf7
A
439 pint_t getIsaVMAddr() const { return A::P::getP(isa); }
440 pint_t setIsaVMAddr(pint_t newIsa) { A::P::setP(isa, newIsa); }
441
442 const char *getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
443
444 uint32_t getSize() const { return A::P::E::get32(size); }
445 void setSize(uint32_t newSize) { A::P::E::set32(size, newSize); }
446
447 uint32_t getFlags() const { return A::P::E::get32(flags); }
448
449 void setFixedUp() { A::P::E::set32(flags, getFlags() | (1<<30)); }
450
451 objc_protocol_list_t<A> *getProtocols(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(protocols)); }
452
412ebb8e 453 objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceMethods)); }
39a8cd10 454
412ebb8e 455 objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(classMethods)); }
39a8cd10 456
412ebb8e 457 objc_method_list_t<A> *getOptionalInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(optionalInstanceMethods)); }
39a8cd10 458
412ebb8e 459 objc_method_list_t<A> *getOptionalClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(optionalClassMethods)); }
39a8cd10 460
df9d6cf7
A
461 objc_property_list_t<A> *getInstanceProperties(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceProperties)); }
462
463 pint_t *getExtendedMethodTypes(SharedCache<A>* cache) const {
464 if (getSize() < offsetof(objc_protocol_t<A>, extendedMethodTypes) + sizeof(extendedMethodTypes)) {
465 return NULL;
466 }
467 return (pint_t *)cache->mappedAddressForVMAddress(A::P::getP(extendedMethodTypes));
468 }
469
470 const char *getDemangledName(SharedCache<A>* cache) const {
471 if (sizeof(*this) < offsetof(objc_protocol_t<A>, demangledName) + sizeof(demangledName)) {
472 return NULL;
473 }
474 return (const char *)cache->mappedAddressForVMAddress(A::P::getP(demangledName));
475 }
476
477 void setDemangledName(SharedCache<A>* cache, const char *newName) {
478 if (sizeof(*this) < offsetof(objc_protocol_t<A>, demangledName) + sizeof(demangledName)) {
479 throw "objc protocol has the wrong size";
480 }
481 A::P::setP(demangledName, cache->VMAddressForMappedAddress(newName));
482 }
483
484 void addPointers(std::vector<void*>& pointersToAdd)
485 {
486 pointersToAdd.push_back(&isa);
487 pointersToAdd.push_back(&name);
488 if (protocols) pointersToAdd.push_back(&protocols);
489 if (instanceMethods) pointersToAdd.push_back(&instanceMethods);
490 if (classMethods) pointersToAdd.push_back(&classMethods);
491 if (optionalInstanceMethods) pointersToAdd.push_back(&optionalInstanceMethods);
492 if (optionalClassMethods) pointersToAdd.push_back(&optionalClassMethods);
493 if (instanceProperties) pointersToAdd.push_back(&instanceProperties);
494 if (extendedMethodTypes) pointersToAdd.push_back(&extendedMethodTypes);
495 if (demangledName) pointersToAdd.push_back(&demangledName);
496 }
39a8cd10
A
497};
498
499template <typename A>
500class objc_protocol_list_t {
412ebb8e
A
501 typedef typename A::P::uint_t pint_t;
502 pint_t count;
503 pint_t list[0];
504
412ebb8e
A
505 void* operator new (size_t, void* buf) { return buf; }
506
507public:
508
509 pint_t getCount() const { return A::P::getP(count); }
510
df9d6cf7
A
511 pint_t getVMAddress(pint_t i) {
512 return A::P::getP(list[i]);
513 }
514
412ebb8e 515 objc_protocol_t<A>* get(SharedCache<A>* cache, pint_t i) {
df9d6cf7
A
516 return (objc_protocol_t<A>*)cache->mappedAddressForVMAddress(getVMAddress(i));
517 }
518
519 void setVMAddress(pint_t i, pint_t protoVMAddr) {
520 A::P::setP(list[i], protoVMAddr);
412ebb8e
A
521 }
522
df9d6cf7
A
523 void set(SharedCache<A>* cache, pint_t i, objc_protocol_t<A>* proto) {
524 setVMAddress(i, cache->VMAddressForMappedAddress(proto));
412ebb8e
A
525 }
526
527 uint32_t byteSize() const {
528 return byteSizeForCount(getCount());
529 }
530 static uint32_t byteSizeForCount(pint_t c) {
531 return sizeof(objc_protocol_list_t<A>) + c*sizeof(pint_t);
532 }
39a8cd10 533
412ebb8e
A
534 void getPointers(std::set<void*>& pointersToRemove) {
535 for(int i=0 ; i < count; ++i) {
536 pointersToRemove.insert(&list[i]);
537 }
538 }
539
540 static void addPointers(uint8_t* protocolList, std::vector<void*>& pointersToAdd) {
541 objc_protocol_list_t<A>* plist = (objc_protocol_list_t<A>*)protocolList;
542 for(int i=0 ; i < plist->count; ++i) {
543 pointersToAdd.push_back(&plist->list[i]);
544 }
545 }
546
547 static objc_protocol_list_t<A>* newProtocolList(pint_t newCount) {
548 void *buf = ::calloc(byteSizeForCount(newCount), 1);
549 return new (buf) objc_protocol_list_t<A>(newCount);
550 }
551
552 void operator delete(void * p) {
553 ::free(p);
554 }
555
556 objc_protocol_list_t(uint32_t newCount) : count(newCount) { }
19894a12
A
557private:
558 // use newProtocolList instead
559 void* operator new (size_t);
412ebb8e 560};
39a8cd10 561
39a8cd10
A
562
563template <typename A>
564class objc_class_data_t {
565 uint32_t flags;
566 uint32_t instanceStart;
412ebb8e
A
567 // Note there is 4-bytes of alignment padding between instanceSize and ivarLayout
568 // on 64-bit archs, but no padding on 32-bit archs.
569 // This union is a way to model that.
570 union {
571 uint32_t instanceSize;
572 typename A::P::uint_t pad;
573 } instanceSize;
39a8cd10
A
574 typename A::P::uint_t ivarLayout;
575 typename A::P::uint_t name;
576 typename A::P::uint_t baseMethods;
577 typename A::P::uint_t baseProtocols;
578 typename A::P::uint_t ivars;
579 typename A::P::uint_t weakIvarLayout;
580 typename A::P::uint_t baseProperties;
581
582public:
832b6fce
A
583 bool isMetaClass() { return A::P::E::get32(flags) & 1; }
584
585 uint32_t getInstanceStart() { return A::P::E::get32(instanceStart); }
586 void setInstanceStart(uint32_t newStart) { A::P::E::set32(instanceStart, newStart); }
587
588 uint32_t getInstanceSize() { return A::P::E::get32(instanceSize.instanceSize); }
589 void setInstanceSize(uint32_t newSiz) { A::P::E::set32(instanceSize.instanceSize, newSiz); }
590
412ebb8e
A
591 objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseMethods)); }
592
593 objc_protocol_list_t<A> *getProtocolList(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProtocols)); }
594
832b6fce
A
595 objc_ivar_list_t<A> *getIvarList(SharedCache<A>* cache) const { return (objc_ivar_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(ivars)); }
596
412ebb8e
A
597 objc_property_list_t<A> *getPropertyList(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProperties)); }
598
599 const char * getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
600
601 void setMethodList(SharedCache<A>* cache, objc_method_list_t<A>* mlist) {
602 A::P::setP(baseMethods, cache->VMAddressForMappedAddress(mlist));
603 }
604
605 void setProtocolList(SharedCache<A>* cache, objc_protocol_list_t<A>* protolist) {
606 A::P::setP(baseProtocols, cache->VMAddressForMappedAddress(protolist));
607 }
608
609 void setPropertyList(SharedCache<A>* cache, objc_property_list_t<A>* proplist) {
610 A::P::setP(baseProperties, cache->VMAddressForMappedAddress(proplist));
611 }
612
613 void addMethodListPointer(std::vector<void*>& pointersToAdd) {
614 pointersToAdd.push_back(&this->baseMethods);
615 }
616
617 void addPropertyListPointer(std::vector<void*>& pointersToAdd) {
618 pointersToAdd.push_back(&this->baseProperties);
619 }
620
621 void addProtocolListPointer(std::vector<void*>& pointersToAdd) {
622 pointersToAdd.push_back(&this->baseProtocols);
623 }
39a8cd10
A
624};
625
626template <typename A>
627class objc_class_t {
628 typename A::P::uint_t isa;
629 typename A::P::uint_t superclass;
630 typename A::P::uint_t method_cache;
631 typename A::P::uint_t vtable;
632 typename A::P::uint_t data;
633
634public:
832b6fce
A
635 bool isMetaClass(SharedCache<A>* cache) const { return getData(cache)->isMetaClass(); }
636
412ebb8e 637 objc_class_t<A> *getIsa(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(isa)); }
39a8cd10 638
832b6fce
A
639 objc_class_t<A> *getSuperclass(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(superclass)); }
640
412ebb8e 641 objc_class_data_t<A> *getData(SharedCache<A>* cache) const { return (objc_class_data_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(data)); }
39a8cd10
A
642
643 objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return getData(cache)->getMethodList(cache); }
412ebb8e
A
644
645 objc_protocol_list_t<A> *getProtocolList(SharedCache<A>* cache) const { return getData(cache)->getProtocolList(cache); }
646
647 objc_property_list_t<A> *getPropertyList(SharedCache<A>* cache) const { return getData(cache)->getPropertyList(cache); }
648
649 const char * getName(SharedCache<A>* cache) const {
650 return getData(cache)->getName(cache);
651 }
652
653 void setMethodList(SharedCache<A>* cache, objc_method_list_t<A>* mlist) {
654 getData(cache)->setMethodList(cache, mlist);
655 }
656
657 void setProtocolList(SharedCache<A>* cache, objc_protocol_list_t<A>* protolist) {
658 getData(cache)->setProtocolList(cache, protolist);
659 }
660
661 void setPropertyList(SharedCache<A>* cache, objc_property_list_t<A>* proplist) {
662 getData(cache)->setPropertyList(cache, proplist);
663 }
664
665 void addMethodListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
666 getData(cache)->addMethodListPointer(pointersToAdd);
667 }
668
669 void addPropertyListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
670 getData(cache)->addPropertyListPointer(pointersToAdd);
671 }
672
673 void addProtocolListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
674 getData(cache)->addProtocolListPointer(pointersToAdd);
675 }
676
39a8cd10
A
677};
678
679
680
681template <typename A>
682class objc_category_t {
683 typename A::P::uint_t name;
684 typename A::P::uint_t cls;
685 typename A::P::uint_t instanceMethods;
686 typename A::P::uint_t classMethods;
687 typename A::P::uint_t protocols;
688 typename A::P::uint_t instanceProperties;
689
690public:
39a8cd10 691
412ebb8e
A
692 const char * getName(SharedCache<A> *cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
693
694 objc_class_t<A> *getClass(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(cls)); }
695
696 objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceMethods)); }
697
698 objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(classMethods)); }
699
700 objc_protocol_list_t<A> *getProtocols(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(protocols)); }
701
702 objc_property_list_t<A> *getInstanceProperties(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceProperties)); }
703
704 void getPointers(std::set<void*>& pointersToRemove) {
705 pointersToRemove.insert(&name);
706 pointersToRemove.insert(&cls);
707 pointersToRemove.insert(&instanceMethods);
708 pointersToRemove.insert(&classMethods);
709 pointersToRemove.insert(&protocols);
710 pointersToRemove.insert(&instanceProperties);
711 }
712
713
39a8cd10
A
714};
715
716template <typename A>
717class objc_message_ref_t {
718 typename A::P::uint_t imp;
719 typename A::P::uint_t sel;
720
721public:
722 typename A::P::uint_t getName() const { return A::P::getP(sel); }
723
724 void setName(typename A::P::uint_t newName) { A::P::setP(sel, newName); }
725};
726
832b6fce
A
727// Call visitor.visitIvar() on every ivar in a given class.
728template <typename A, typename V>
729class IvarWalker {
730 typedef typename A::P P;
731 typedef typename A::P::uint_t pint_t;
732 V& ivarVisitor;
733public:
734
735 IvarWalker(V& visitor) : ivarVisitor(visitor) { }
736
737 void walk(SharedCache<A>* cache, const macho_header<P>* header, objc_class_t<A> *cls)
738 {
739 objc_class_data_t<A> *data = cls->getData(cache);
740 objc_ivar_list_t<A> *ivars = data->getIvarList(cache);
741 if (ivars) {
742 for (pint_t i = 0; i < ivars->getCount(); i++) {
743 objc_ivar_t<A>& ivar = ivars->get(i);
744 //fprintf(stderr, "visiting ivar: %s\n", ivar.getName(cache));
745 ivarVisitor.visitIvar(cache, header, cls, &ivar);
746 }
747 } else {
748 //fprintf(stderr, "no ivars\n");
749 }
750 }
751
752 void visitClass(SharedCache<A>* cache, const macho_header<P>* header, objc_class_t<A> *cls)
753 {
754 walk(cache, header, cls);
755 }
756};
757
758// Call visitor.visitClass() on every class.
759template <typename A, typename V>
760class ClassWalker {
761 typedef typename A::P P;
762 typedef typename A::P::uint_t pint_t;
763 V& classVisitor;
764public:
765
766 ClassWalker(V& visitor) : classVisitor(visitor) { }
767
768 void walk(SharedCache<A>* cache, const macho_header<P>* header)
769 {
770 PointerSection<A, objc_class_t<A> *>
771 classes(cache, header, "__DATA", "__objc_classlist");
772
773 for (pint_t i = 0; i < classes.count(); i++) {
774 objc_class_t<A> *cls = classes.get(i);
775 //fprintf(stderr, "visiting class: %s\n", cls->getName(cache));
df9d6cf7
A
776 if (cls) classVisitor.visitClass(cache, header, cls);
777 }
778 }
779};
780
781
782// Call visitor.visitProtocol() on every protocol.
783template <typename A, typename V>
784class ProtocolWalker {
785 typedef typename A::P P;
786 typedef typename A::P::uint_t pint_t;
787 V& protocolVisitor;
788public:
789
790 ProtocolWalker(V& visitor) : protocolVisitor(visitor) { }
791
792 void walk(SharedCache<A>* cache, const macho_header<P>* header)
793 {
794 PointerSection<A, objc_protocol_t<A> *>
795 protocols(cache, header, "__DATA", "__objc_protolist");
796
797 for (pint_t i = 0; i < protocols.count(); i++) {
798 objc_protocol_t<A> *proto = protocols.get(i);
799 protocolVisitor.visitProtocol(cache, header, proto);
800 }
801 }
802};
803
804
805// Call visitor.visitProtocolReference() on every protocol.
806template <typename A, typename V>
807class ProtocolReferenceWalker {
808 typedef typename A::P P;
809 typedef typename A::P::uint_t pint_t;
810 V& mVisitor;
811
812 void visitProtocolList(SharedCache<A>* cache,
813 objc_protocol_list_t<A>* protolist)
814 {
815 if (!protolist) return;
816 for (pint_t i = 0; i < protolist->getCount(); i++) {
817 pint_t oldValue = protolist->getVMAddress(i);
818 pint_t newValue = mVisitor.visitProtocolReference(cache, oldValue);
819 protolist->setVMAddress(i, newValue);
820 }
821 }
822
823 friend class ClassWalker<A, ProtocolReferenceWalker<A, V>>;
824 void visitClass(SharedCache<A>* cache, const macho_header<P>*,
825 objc_class_t<A>* cls)
826 {
827 visitProtocolList(cache, cls->getProtocolList(cache));
828 visitProtocolList(cache, cls->getIsa(cache)->getProtocolList(cache));
829 }
830
831public:
832
833 ProtocolReferenceWalker(V& visitor) : mVisitor(visitor) { }
834 void walk(SharedCache<A>* cache, const macho_header<P>* header)
835 {
836 // @protocol expressions
837 PointerSection<A, objc_protocol_t<A> *>
838 protorefs(cache, header, "__DATA", "__objc_protorefs");
839 for (pint_t i = 0; i < protorefs.count(); i++) {
840 pint_t oldValue = protorefs.getVMAddress(i);
841 pint_t newValue = mVisitor.visitProtocolReference(cache, oldValue);
842 protorefs.setVMAddress(i, newValue);
843 }
844
845 // protocol lists in classes
846 ClassWalker<A, ProtocolReferenceWalker<A, V>> classes(*this);
847 classes.walk(cache, header);
848
849 // protocol lists in protocols
850 // __objc_protolists itself is NOT updated
851 PointerSection<A, objc_protocol_t<A> *>
852 protocols(cache, header, "__DATA", "__objc_protolist");
853 for (pint_t i = 0; i < protocols.count(); i++) {
854 objc_protocol_t<A>* proto = protocols.get(i);
855 visitProtocolList(cache, proto->getProtocols(cache));
856 // not recursive: every old protocol object
857 // must be in some protolist section somewhere
832b6fce
A
858 }
859 }
860};
861
412ebb8e 862
df9d6cf7
A
863// Call visitor.visitMethodList(mlist) on every
864// class and category method list in a header.
865// Call visitor.visitProtocolMethodList(mlist, typelist) on every
866// protocol method list in a header.
39a8cd10 867template <typename A, typename V>
412ebb8e 868class MethodListWalker {
39a8cd10
A
869
870 typedef typename A::P P;
871 typedef typename A::P::uint_t pint_t;
872
412ebb8e 873 V& mVisitor;
39a8cd10 874
412ebb8e
A
875public:
876
877 MethodListWalker(V& visitor) : mVisitor(visitor) { }
39a8cd10 878
df9d6cf7 879 void walk(SharedCache<A>* cache, const macho_header<P>* header)
412ebb8e 880 {
39a8cd10
A
881 // Method lists in classes
882 PointerSection<A, objc_class_t<A> *>
883 classes(cache, header, "__DATA", "__objc_classlist");
412ebb8e 884
39a8cd10
A
885 for (pint_t i = 0; i < classes.count(); i++) {
886 objc_class_t<A> *cls = classes.get(i);
887 objc_method_list_t<A> *mlist;
888 if ((mlist = cls->getMethodList(cache))) {
412ebb8e 889 mVisitor.visitMethodList(mlist);
39a8cd10
A
890 }
891 if ((mlist = cls->getIsa(cache)->getMethodList(cache))) {
412ebb8e 892 mVisitor.visitMethodList(mlist);
39a8cd10
A
893 }
894 }
895
896 // Method lists from categories
897 PointerSection<A, objc_category_t<A> *>
898 cats(cache, header, "__DATA", "__objc_catlist");
899 for (pint_t i = 0; i < cats.count(); i++) {
900 objc_category_t<A> *cat = cats.get(i);
901 objc_method_list_t<A> *mlist;
902 if ((mlist = cat->getInstanceMethods(cache))) {
412ebb8e 903 mVisitor.visitMethodList(mlist);
39a8cd10
A
904 }
905 if ((mlist = cat->getClassMethods(cache))) {
412ebb8e 906 mVisitor.visitMethodList(mlist);
39a8cd10
A
907 }
908 }
909
df9d6cf7
A
910 // Method description lists from protocols
911 PointerSection<A, objc_protocol_t<A> *>
912 protocols(cache, header, "__DATA", "__objc_protolist");
913 for (pint_t i = 0; i < protocols.count(); i++) {
914 objc_protocol_t<A> *proto = protocols.get(i);
915 objc_method_list_t<A> *mlist;
916 pint_t *typelist = proto->getExtendedMethodTypes(cache);
917
918 if ((mlist = proto->getInstanceMethods(cache))) {
919 mVisitor.visitProtocolMethodList(mlist, typelist);
920 if (typelist) typelist += mlist->getCount();
921 }
922 if ((mlist = proto->getClassMethods(cache))) {
923 mVisitor.visitProtocolMethodList(mlist, typelist);
924 if (typelist) typelist += mlist->getCount();
925 }
926 if ((mlist = proto->getOptionalInstanceMethods(cache))) {
927 mVisitor.visitProtocolMethodList(mlist, typelist);
928 if (typelist) typelist += mlist->getCount();
929 }
930 if ((mlist = proto->getOptionalClassMethods(cache))) {
931 mVisitor.visitProtocolMethodList(mlist, typelist);
932 if (typelist) typelist += mlist->getCount();
933 }
934 }
412ebb8e
A
935 }
936};
39a8cd10 937
412ebb8e
A
938
939// Update selector references. The visitor performs recording and uniquing.
940template <typename A, typename V>
941class SelectorOptimizer {
942
943 typedef typename A::P P;
944 typedef typename A::P::uint_t pint_t;
945
946 V& mVisitor;
947
948 friend class MethodListWalker< A, SelectorOptimizer<A,V> >;
949 void visitMethodList(objc_method_list_t<A> *mlist)
950 {
951 // Gather selectors. Update method names.
952 for (pint_t m = 0; m < mlist->getCount(); m++) {
953 pint_t oldValue = mlist->get(m).getName();
954 pint_t newValue = mVisitor.visit(oldValue);
955 mlist->get(m).setName(newValue);
956 }
957 // Do not setFixedUp: the methods are not yet sorted.
958 }
959
df9d6cf7
A
960 void visitProtocolMethodList(objc_method_list_t<A> *mlist, pint_t *types)
961 {
962 visitMethodList(mlist);
963 }
964
412ebb8e
A
965public:
966
967 SelectorOptimizer(V& visitor) : mVisitor(visitor) { }
968
969 void optimize(SharedCache<A>* cache, const macho_header<P>* header)
970 {
df9d6cf7 971 // method lists in classes, categories, and protocols
412ebb8e 972 MethodListWalker< A, SelectorOptimizer<A,V> > mw(*this);
df9d6cf7 973 mw.walk(cache, header);
412ebb8e 974
39a8cd10
A
975 // @selector references
976 PointerSection<A, const char *>
977 selrefs(cache, header, "__DATA", "__objc_selrefs");
978 for (pint_t i = 0; i < selrefs.count(); i++) {
df9d6cf7 979 pint_t oldValue = selrefs.getVMAddress(i);
412ebb8e 980 pint_t newValue = mVisitor.visit(oldValue);
df9d6cf7 981 selrefs.setVMAddress(i, newValue);
39a8cd10
A
982 }
983
984 // message references
985 ArraySection<A, objc_message_ref_t<A> >
986 msgrefs(cache, header, "__DATA", "__objc_msgrefs");
987 for (pint_t i = 0; i < msgrefs.count(); i++) {
988 objc_message_ref_t<A>& msg = msgrefs.get(i);
989 pint_t oldValue = msg.getName();
412ebb8e 990 pint_t newValue = mVisitor.visit(oldValue);
39a8cd10
A
991 msg.setName(newValue);
992 }
832b6fce
A
993 }
994};
39a8cd10 995
832b6fce 996
df9d6cf7
A
997template <typename A>
998static bool headerSupportsGC(SharedCache<A>* cache,
999 const macho_header<typename A::P>* header)
1000{
1001 const macho_section<typename A::P> *imageInfoSection =
1002 header->getSection("__DATA", "__objc_imageinfo");
1003 if (imageInfoSection) {
1004 objc_image_info<A> *info = (objc_image_info<A> *)
1005 cache->mappedAddressForVMAddress(imageInfoSection->addr());
1006 return (info->supportsGCFlagSet() || info->requiresGCFlagSet());
1007 }
1008
1009 return false;
1010}
1011
1012
1013// Gather the set of GC-supporting classes
1014template <typename A>
1015class GCClassSet {
1016 typedef typename A::P P;
1017
1018 std::set<objc_class_t<A>*> fGCClasses;
1019
1020public:
1021 bool contains(objc_class_t<A>* cls) const {
1022 return fGCClasses.count(cls) != 0;
1023 }
1024
1025 void visitClass(SharedCache<A>* cache, const macho_header<P>* header, objc_class_t<A> *cls)
1026 {
1027 fGCClasses.insert(cls);
1028 }
1029};
1030
1031
832b6fce
A
1032// Update selector references. The visitor performs recording and uniquing.
1033template <typename A>
1034class IvarOffsetOptimizer {
1035 typedef typename A::P P;
1036
1037 uint32_t slide;
1038 uint32_t maxAlignment;
1039
1040 uint32_t fOptimized;
1041
df9d6cf7
A
1042 GCClassSet<A> fGCClasses;
1043
832b6fce
A
1044public:
1045
1046 IvarOffsetOptimizer() : fOptimized(0) { }
1047
1048 size_t optimized() const { return fOptimized; }
1049
1050 // dual purpose ivar visitor function
1051 // if slide!=0 then slides the ivar by that amount, otherwise computes maxAlignment
1052 void visitIvar(SharedCache<A>* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<A> *cls, objc_ivar_t<A> *ivar)
1053 {
1054 if (slide == 0) {
1055 uint32_t alignment = ivar->getAlignment();
1056 if (alignment > maxAlignment) maxAlignment = alignment;
1057 } else {
1058 // skip anonymous bitfields
1059 if (ivar->hasOffset()) {
1060 uint32_t oldOffset = (uint32_t)ivar->getOffset(cache);
1061 ivar->setOffset(cache, oldOffset + slide);
1062 fOptimized++;
1063 //fprintf(stderr, "%d -> %d for %s.%s\n", oldOffset, oldOffset + slide, cls->getName(cache), ivar->getName(cache));
1064 } else {
1065 //fprintf(stderr, "NULL offset\n");
1066 }
1067 }
1068 }
1069
1070 // Class visitor function. Evaluates whether to slide ivars and performs slide if needed.
1071 // The slide algorithm is also implemented in objc. Any changes here should be reflected there also.
1072 void visitClass(SharedCache<A>* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<A> *cls)
1073 {
df9d6cf7
A
1074 if (fGCClasses.contains(cls)) {
1075 // This class supports GC. We don't know how to update
1076 // GC ivar layout bitmaps, so don't touch anything.
1077 return;
1078 }
1079
832b6fce
A
1080 objc_class_t<A> *super = cls->getSuperclass(cache);
1081 if (super) {
1082 // Recursively visit superclasses to ensure we have the correct superclass start
1083 // Note that we don't need the macho_header, so just pass NULL.
1084 visitClass(cache, NULL, super);
1085
1086 objc_class_data_t<A> *data = cls->getData(cache);
1087 objc_class_data_t<A> *super_data = super->getData(cache);
1088 int32_t diff = super_data->getInstanceSize() - data->getInstanceStart();
1089 if (diff > 0) {
1090 IvarWalker<A, IvarOffsetOptimizer<A> > ivarVisitor(*this);
1091 maxAlignment = 0;
1092 slide = 0;
1093
1094 // This walk computes maxAlignment
1095 ivarVisitor.walk(cache, NULL, cls);
1096
1097 // Compute a slide value that preserves that alignment
1098 uint32_t alignMask = maxAlignment - 1;
1099 if (diff & alignMask) diff = (diff + alignMask) & ~alignMask;
1100
1101 // Slide all of this class's ivars en masse
1102 slide = diff;
1103 if (slide != 0) {
1104 //fprintf(stderr, "Sliding ivars in %s by %u (superclass was %d, now %d)\n", cls->getName(cache), slide, data->getInstanceStart(), super_data->getInstanceSize());
1105 ivarVisitor.walk(cache, NULL, cls);
1106 data->setInstanceStart(data->getInstanceStart() + slide);
1107 data->setInstanceSize(data->getInstanceSize() + slide);
1108 }
1109 }
1110 }
1111 }
df9d6cf7
A
1112
1113 // Gather the list of GC-supporting classes.
1114 // Ivars in these classes cannot be updated because
1115 // we don't know how to update ivar layout bitmaps.
1116 void findGCClasses(SharedCache<A>* cache, const macho_header<P>* header)
1117 {
1118 if (headerSupportsGC(cache, header)) {
1119 ClassWalker<A, GCClassSet<A> > classVisitor(fGCClasses);
1120 classVisitor.walk(cache, header);
1121 }
1122 }
1123
832b6fce
A
1124 // Enumerates objc classes in the module and performs any ivar slides
1125 void optimize(SharedCache<A>* cache, const macho_header<P>* header)
1126 {
df9d6cf7
A
1127 if (! headerSupportsGC(cache, header)) {
1128 ClassWalker<A, IvarOffsetOptimizer<A> > classVisitor(*this);
1129 classVisitor.walk(cache, header);
39a8cd10
A
1130 }
1131 }
1132};
412ebb8e
A
1133
1134
1135// Sort methods in place by selector.
1136template <typename A>
1137class MethodListSorter {
1138
1139 typedef typename A::P P;
1140 typedef typename A::P::uint_t pint_t;
1141
832b6fce
A
1142 uint32_t fOptimized;
1143
412ebb8e
A
1144 friend class MethodListWalker<A, MethodListSorter<A> >;
1145 void visitMethodList(objc_method_list_t<A> *mlist)
1146 {
1147 typename objc_method_t<A>::SortBySELAddress sorter;
1148 std::stable_sort(mlist->begin(), mlist->end(), sorter);
1149 mlist->setFixedUp();
832b6fce 1150 fOptimized++;
412ebb8e
A
1151 }
1152
df9d6cf7
A
1153 void visitProtocolMethodList(objc_method_list_t<A> *mlist, pint_t *typelist)
1154 {
1155 typename objc_method_t<A>::SortBySELAddress sorter;
1156 // can't easily use std::stable_sort here
1157 for (uint32_t i = 0; i < mlist->getCount(); i++) {
1158 for (uint32_t j = i+1; j < mlist->getCount(); j++) {
1159 objc_method_t<A>& mi = mlist->get(i);
1160 objc_method_t<A>& mj = mlist->get(j);
1161 if (! sorter(mi, mj)) {
1162 std::swap(mi, mj);
1163 if (typelist) std::swap(typelist[i], typelist[j]);
1164 }
1165 }
1166 }
1167
1168 mlist->setFixedUp();
1169 fOptimized++;
1170 }
1171
412ebb8e 1172public:
832b6fce
A
1173 MethodListSorter() : fOptimized(0) { }
1174
1175 size_t optimized() const { return fOptimized; }
412ebb8e
A
1176
1177 void optimize(SharedCache<A>* cache, macho_header<P>* header)
1178 {
1179 MethodListWalker<A, MethodListSorter<A> > mw(*this);
df9d6cf7 1180 mw.walk(cache, header);
412ebb8e
A
1181 }
1182};
1183
1184
412ebb8e 1185template <typename A>
832b6fce 1186class HeaderInfoOptimizer {
412ebb8e
A
1187
1188 typedef typename A::P P;
1189 typedef typename A::P::uint_t pint_t;
1190
832b6fce
A
1191 objc_header_info_t<A>* fHinfos;
1192 size_t fCount;
412ebb8e 1193
832b6fce
A
1194public:
1195 HeaderInfoOptimizer() : fHinfos(0), fCount(0) { }
412ebb8e 1196
832b6fce 1197 const char *init(size_t count, uint8_t*& buf, size_t& bufSize)
412ebb8e 1198 {
832b6fce 1199 if (count == 0) return NULL;
412ebb8e 1200
df9d6cf7
A
1201 size_t requiredSize =
1202 2*sizeof(uint32_t) + count*sizeof(objc_header_info_t<A>);
1203 if (bufSize < requiredSize) {
832b6fce 1204 return "libobjc's read/write section is too small (metadata not optimized)";
412ebb8e 1205 }
412ebb8e 1206
832b6fce
A
1207 uint32_t *buf32 = (uint32_t *)buf;
1208 A::P::E::set32(buf32[0], count);
1209 A::P::E::set32(buf32[1], sizeof(objc_header_info_t<A>));
1210 fHinfos = (objc_header_info_t<A>*)(buf32+2);
412ebb8e 1211
df9d6cf7
A
1212 buf += requiredSize;
1213 bufSize -= requiredSize;
412ebb8e 1214
832b6fce 1215 return NULL;
412ebb8e
A
1216 }
1217
832b6fce
A
1218 void update(SharedCache<A>* cache, const macho_header<P>* mh, std::vector<void*>& pointersInData)
1219 {
1220 objc_header_info_t<A>* hi = new(&fHinfos[fCount++]) objc_header_info_t<A>(cache, mh);
1221 hi->addPointers(pointersInData);
412ebb8e
A
1222 }
1223
832b6fce 1224 objc_header_info_t<A>* hinfoForHeader(SharedCache<A>* cache, const macho_header<P>* mh)
412ebb8e 1225 {
832b6fce
A
1226 // fixme could be binary search
1227 pint_t mh_vmaddr = cache->VMAddressForMappedAddress(mh);
1228 for (size_t i = 0; i < fCount; i++) {
1229 objc_header_info_t<A>* hi = &fHinfos[i];
1230 if (hi->header_vmaddr() == mh_vmaddr) return hi;
412ebb8e 1231 }
412ebb8e
A
1232 return NULL;
1233 }
412ebb8e 1234};