]> git.saurik.com Git - apple/dyld.git/blob - launch-cache/ObjCModernAbstraction.hpp
9dc9b90adcad59e5de6a99df4658d0047a581f5f
[apple/dyld.git] / launch-cache / ObjCModernAbstraction.hpp
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 <iterator>
26 #include <deque>
27
28 // iterate an entsize-based list
29 // typedef entsize_iterator< A, type_t<A>, type_list_t<A> > type_iterator;
30 template <typename A, typename T, typename Tlist>
31 struct entsize_iterator {
32 uint32_t entsize;
33 uint32_t index; // keeping track of this saves a divide in operator-
34 T* current;
35
36 typedef std::random_access_iterator_tag iterator_category;
37 typedef T value_type;
38 typedef ptrdiff_t difference_type;
39 typedef T* pointer;
40 typedef T& reference;
41
42 entsize_iterator() { }
43
44 entsize_iterator(const Tlist& list, uint32_t start = 0)
45 : entsize(list.getEntsize()), index(start), current(&list.get(start))
46 { }
47
48 const entsize_iterator<A,T,Tlist>& operator += (ptrdiff_t count) {
49 current = (T*)((uint8_t *)current + count*entsize);
50 index += count;
51 return *this;
52 }
53 const entsize_iterator<A,T,Tlist>& operator -= (ptrdiff_t count) {
54 current = (T*)((uint8_t *)current - count*entsize);
55 index -= count;
56 return *this;
57 }
58 const entsize_iterator<A,T,Tlist> operator + (ptrdiff_t count) const {
59 return entsize_iterator(*this) += count;
60 }
61 const entsize_iterator<A,T,Tlist> operator - (ptrdiff_t count) const {
62 return entsize_iterator(*this) -= count;
63 }
64
65 entsize_iterator<A,T,Tlist>& operator ++ () { *this += 1; return *this; }
66 entsize_iterator<A,T,Tlist>& operator -- () { *this -= 1; return *this; }
67 entsize_iterator<A,T,Tlist> operator ++ (int) {
68 entsize_iterator<A,T,Tlist> result(*this); *this += 1; return result;
69 }
70 entsize_iterator<A,T,Tlist> operator -- (int) {
71 entsize_iterator<A,T,Tlist> result(*this); *this -= 1; return result;
72 }
73
74 ptrdiff_t operator - (const entsize_iterator<A,T,Tlist>& rhs) const {
75 return (ptrdiff_t)this->index - (ptrdiff_t)rhs.index;
76 }
77
78 T& operator * () { return *current; }
79 const T& operator * () const { return *current; }
80 T& operator -> () { return *current; }
81 const T& operator -> () const { return *current; }
82
83 operator T& () const { return *current; }
84
85 bool operator == (const entsize_iterator<A,T,Tlist>& rhs) {
86 return this->current == rhs.current;
87 }
88 bool operator != (const entsize_iterator<A,T,Tlist>& rhs) {
89 return this->current != rhs.current;
90 }
91
92 bool operator < (const entsize_iterator<A,T,Tlist>& rhs) {
93 return this->current < rhs.current;
94 }
95 bool operator > (const entsize_iterator<A,T,Tlist>& rhs) {
96 return this->current > rhs.current;
97 }
98
99
100 static void overwrite(entsize_iterator<A,T,Tlist>& dst, const Tlist* srcList)
101 {
102 entsize_iterator<A,T,Tlist> src;
103 uint32_t ee = srcList->getEntsize();
104 for (src = srcList->begin(); src != srcList->end(); ++src) {
105 memcpy(&*dst, &*src, ee);
106 ++dst;
107 }
108 }
109 };
110
111 template <typename A> class objc_method_list_t; // forward reference
112
113 template <typename A>
114 class objc_method_t {
115 typename A::P::uint_t name; // SEL
116 typename A::P::uint_t types; // const char *
117 typename A::P::uint_t imp; // IMP
118 friend class objc_method_list_t<A>;
119 public:
120 typename A::P::uint_t getName() const { return A::P::getP(name); }
121 void setName(typename A::P::uint_t newName) { A::P::setP(name, newName); }
122
123 struct SortBySELAddress :
124 public std::binary_function<const objc_method_t<A>&,
125 const objc_method_t<A>&, bool>
126 {
127 bool operator() (const objc_method_t<A>& lhs,
128 const objc_method_t<A>& rhs)
129 {
130 return lhs.getName() < rhs.getName();
131 }
132 };
133 };
134
135 template <typename A>
136 class objc_method_list_t {
137 uint32_t entsize;
138 uint32_t count;
139 objc_method_t<A> first;
140
141 // use newMethodList instead
142 void* operator new (size_t) { return NULL; }
143 void* operator new (size_t, void* buf) { return buf; }
144
145 public:
146
147 typedef entsize_iterator< A, objc_method_t<A>, objc_method_list_t<A> > method_iterator;
148
149 uint32_t getCount() const { return A::P::E::get32(count); }
150
151 uint32_t getEntsize() const {return A::P::E::get32(entsize)&~(uint32_t)3;}
152
153 objc_method_t<A>& get(uint32_t i) const { return *(objc_method_t<A> *)((uint8_t *)&first + i * getEntsize()); }
154
155 uint32_t byteSize() const {
156 return byteSizeForCount(getCount(), getEntsize());
157 }
158
159 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_method_t<A>)) {
160 return sizeof(objc_method_list_t<A>) - sizeof(objc_method_t<A>) + c*e;
161 }
162
163 method_iterator begin() { return method_iterator(*this, 0); }
164 method_iterator end() { return method_iterator(*this, getCount()); }
165 const method_iterator begin() const { return method_iterator(*this, 0); }
166 const method_iterator end() const { return method_iterator(*this, getCount()); }
167
168 void setFixedUp() { A::P::E::set32(entsize, getEntsize() | 3); }
169
170 void getPointers(std::set<void*>& pointersToRemove) {
171 for(method_iterator it = begin(); it != end(); ++it) {
172 objc_method_t<A>& entry = *it;
173 pointersToRemove.insert(&(entry.name));
174 pointersToRemove.insert(&(entry.types));
175 pointersToRemove.insert(&(entry.imp));
176 }
177 }
178
179 static void addPointers(uint8_t* methodList, std::vector<void*>& pointersToAdd) {
180 objc_method_list_t<A>* mlist = (objc_method_list_t<A>*)methodList;
181 for(method_iterator it = mlist->begin(); it != mlist->end(); ++it) {
182 objc_method_t<A>& entry = *it;
183 pointersToAdd.push_back(&(entry.name));
184 pointersToAdd.push_back(&(entry.types));
185 pointersToAdd.push_back(&(entry.imp));
186 }
187 }
188
189 static objc_method_list_t<A>* newMethodList(size_t newCount, uint32_t newEntsize) {
190 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
191 return new (buf) objc_method_list_t<A>(newCount, newEntsize);
192 }
193
194 void operator delete(void * p) {
195 ::free(p);
196 }
197
198 objc_method_list_t(uint32_t newCount,
199 uint32_t newEntsize = sizeof(objc_method_t<A>))
200 : entsize(newEntsize), count(newCount)
201 { }
202 };
203
204 template <typename A>
205 class objc_ivar_t {
206 typename A::P::uint_t offset; // A::P *
207 typename A::P::uint_t name; // const char *
208 typename A::P::uint_t type; // const char *
209 uint32_t alignment;
210 uint32_t size;
211 };
212
213 template <typename A>
214 class objc_ivar_list_t {
215 uint32_t entsize;
216 uint32_t count;
217 objc_ivar_t<A> first;
218
219 // use newIvarList instead
220 void* operator new (size_t) { return NULL; }
221 void* operator new (size_t, void* buf) { return buf; }
222
223 public:
224
225 typedef entsize_iterator< A, objc_ivar_t<A>, objc_ivar_list_t<A> > ivar_iterator;
226
227 uint32_t getCount() const { return A::P::E::get32(count); }
228
229 uint32_t getEntsize() const { return A::P::E::get32(entsize); }
230
231 objc_ivar_t<A>& get(typename A::P::pint_t i) const { return *(objc_ivar_t<A> *)((uint8_t *)&first + i * A::P::E::get32(entsize)); }
232
233 uint32_t byteSize() const {
234 return byteSizeForCount(getCount(), getEntsize());
235 }
236
237 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_ivar_t<A>)) {
238 return sizeof(objc_ivar_list_t<A>) - sizeof(objc_ivar_t<A>) + c*e;
239 }
240
241 ivar_iterator begin() { return ivar_iterator(*this, 0); }
242 ivar_iterator end() { return ivar_iterator(*this, getCount()); }
243 const ivar_iterator begin() const { return ivar_iterator(*this, 0); }
244 const ivar_iterator end() const { return ivar_iterator(*this, getCount()); }
245
246 static objc_ivar_list_t<A>* newIvarList(size_t newCount, uint32_t newEntsize) {
247 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
248 return new (buf) objc_ivar_list_t<A>(newCount, newEntsize);
249 }
250
251 void operator delete(void * p) {
252 ::free(p);
253 }
254
255 objc_ivar_list_t(uint32_t newCount,
256 uint32_t newEntsize = sizeof(objc_ivar_t<A>))
257 : entsize(newEntsize), count(newCount)
258 { }
259
260 };
261
262
263 template <typename A> class objc_property_list_t; // forward
264
265 template <typename A>
266 class objc_property_t {
267 typename A::P::uint_t name;
268 typename A::P::uint_t attributes;
269 friend class objc_property_list_t<A>;
270 public:
271
272 const char * getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
273
274 const char * getAttributes(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(attributes)); }
275 };
276
277 template <typename A>
278 class objc_property_list_t {
279 uint32_t entsize;
280 uint32_t count;
281 objc_property_t<A> first;
282
283 // use newPropertyList instead
284 void* operator new (size_t) { return NULL; }
285 void* operator new (size_t, void* buf) { return buf; }
286
287 public:
288
289 typedef entsize_iterator< A, objc_property_t<A>, objc_property_list_t<A> > property_iterator;
290
291 uint32_t getCount() const { return A::P::E::get32(count); }
292
293 uint32_t getEntsize() const { return A::P::E::get32(entsize); }
294
295 objc_property_t<A>& get(uint32_t i) const { return *(objc_property_t<A> *)((uint8_t *)&first + i * getEntsize()); }
296
297 uint32_t byteSize() const {
298 return byteSizeForCount(getCount(), getEntsize());
299 }
300
301 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_property_t<A>)) {
302 return sizeof(objc_property_list_t<A>) - sizeof(objc_property_t<A>) + c*e;
303 }
304
305 property_iterator begin() { return property_iterator(*this, 0); }
306 property_iterator end() { return property_iterator(*this, getCount()); }
307 const property_iterator begin() const { return property_iterator(*this, 0); }
308 const property_iterator end() const { return property_iterator(*this, getCount()); }
309
310 void getPointers(std::set<void*>& pointersToRemove) {
311 for(property_iterator it = begin(); it != end(); ++it) {
312 objc_property_t<A>& entry = *it;
313 pointersToRemove.insert(&(entry.name));
314 pointersToRemove.insert(&(entry.attributes));
315 }
316 }
317
318 static void addPointers(uint8_t* propertyList, std::vector<void*>& pointersToAdd) {
319 objc_property_list_t<A>* plist = (objc_property_list_t<A>*)propertyList;
320 for(property_iterator it = plist->begin(); it != plist->end(); ++it) {
321 objc_property_t<A>& entry = *it;
322 pointersToAdd.push_back(&(entry.name));
323 pointersToAdd.push_back(&(entry.attributes));
324 }
325 }
326
327 static objc_property_list_t<A>* newPropertyList(size_t newCount, uint32_t newEntsize) {
328 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
329 return new (buf) objc_property_list_t<A>(newCount, newEntsize);
330 }
331
332 void operator delete(void * p) {
333 ::free(p);
334 }
335
336 objc_property_list_t(uint32_t newCount,
337 uint32_t newEntsize = sizeof(objc_property_t<A>))
338 : entsize(newEntsize), count(newCount)
339 { }
340
341 };
342
343 template <typename A>
344 class objc_protocol_t {
345 typename A::P::uint_t isa;
346 typename A::P::uint_t name;
347 typename A::P::uint_t protocols;
348 typename A::P::uint_t instanceMethods;
349 typename A::P::uint_t classMethods;
350 typename A::P::uint_t optionalInstanceMethods;
351 typename A::P::uint_t optionalClassMethods;
352 typename A::P::uint_t instanceProperties;
353
354 public:
355 objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceMethods)); }
356
357 objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(classMethods)); }
358
359 objc_method_list_t<A> *getOptionalInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(optionalInstanceMethods)); }
360
361 objc_method_list_t<A> *getOptionalClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(optionalClassMethods)); }
362
363 };
364
365 template <typename A>
366 class objc_protocol_list_t {
367 typedef typename A::P::uint_t pint_t;
368 pint_t count;
369 pint_t list[0];
370
371 // use newProtocolList instead
372 void* operator new (size_t) { return NULL; }
373 void* operator new (size_t, void* buf) { return buf; }
374
375 public:
376
377 pint_t getCount() const { return A::P::getP(count); }
378
379 objc_protocol_t<A>* get(SharedCache<A>* cache, pint_t i) {
380 return (objc_protocol_t<A>*)cache->mappedAddressForVMAddress(A::P::getP(list[i]));
381 }
382
383 void overwrite(pint_t& index, const objc_protocol_list_t<A>* src) {
384 pint_t srcCount = src->getCount();
385 memcpy(list+index, src->list, srcCount * sizeof(pint_t));
386 index += srcCount;
387 }
388
389 uint32_t byteSize() const {
390 return byteSizeForCount(getCount());
391 }
392 static uint32_t byteSizeForCount(pint_t c) {
393 return sizeof(objc_protocol_list_t<A>) + c*sizeof(pint_t);
394 }
395
396 void getPointers(std::set<void*>& pointersToRemove) {
397 for(int i=0 ; i < count; ++i) {
398 pointersToRemove.insert(&list[i]);
399 }
400 }
401
402 static void addPointers(uint8_t* protocolList, std::vector<void*>& pointersToAdd) {
403 objc_protocol_list_t<A>* plist = (objc_protocol_list_t<A>*)protocolList;
404 for(int i=0 ; i < plist->count; ++i) {
405 pointersToAdd.push_back(&plist->list[i]);
406 }
407 }
408
409 static objc_protocol_list_t<A>* newProtocolList(pint_t newCount) {
410 void *buf = ::calloc(byteSizeForCount(newCount), 1);
411 return new (buf) objc_protocol_list_t<A>(newCount);
412 }
413
414 void operator delete(void * p) {
415 ::free(p);
416 }
417
418 objc_protocol_list_t(uint32_t newCount) : count(newCount) { }
419
420 };
421
422
423 template <typename A>
424 class objc_class_data_t {
425 uint32_t flags;
426 uint32_t instanceStart;
427 // Note there is 4-bytes of alignment padding between instanceSize and ivarLayout
428 // on 64-bit archs, but no padding on 32-bit archs.
429 // This union is a way to model that.
430 union {
431 uint32_t instanceSize;
432 typename A::P::uint_t pad;
433 } instanceSize;
434 typename A::P::uint_t ivarLayout;
435 typename A::P::uint_t name;
436 typename A::P::uint_t baseMethods;
437 typename A::P::uint_t baseProtocols;
438 typename A::P::uint_t ivars;
439 typename A::P::uint_t weakIvarLayout;
440 typename A::P::uint_t baseProperties;
441
442 public:
443 objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseMethods)); }
444
445 objc_protocol_list_t<A> *getProtocolList(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProtocols)); }
446
447 objc_property_list_t<A> *getPropertyList(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProperties)); }
448
449 const char * getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
450
451 void setMethodList(SharedCache<A>* cache, objc_method_list_t<A>* mlist) {
452 A::P::setP(baseMethods, cache->VMAddressForMappedAddress(mlist));
453 }
454
455 void setProtocolList(SharedCache<A>* cache, objc_protocol_list_t<A>* protolist) {
456 A::P::setP(baseProtocols, cache->VMAddressForMappedAddress(protolist));
457 }
458
459 void setPropertyList(SharedCache<A>* cache, objc_property_list_t<A>* proplist) {
460 A::P::setP(baseProperties, cache->VMAddressForMappedAddress(proplist));
461 }
462
463 void addMethodListPointer(std::vector<void*>& pointersToAdd) {
464 pointersToAdd.push_back(&this->baseMethods);
465 }
466
467 void addPropertyListPointer(std::vector<void*>& pointersToAdd) {
468 pointersToAdd.push_back(&this->baseProperties);
469 }
470
471 void addProtocolListPointer(std::vector<void*>& pointersToAdd) {
472 pointersToAdd.push_back(&this->baseProtocols);
473 }
474 };
475
476 template <typename A>
477 class objc_class_t {
478 typename A::P::uint_t isa;
479 typename A::P::uint_t superclass;
480 typename A::P::uint_t method_cache;
481 typename A::P::uint_t vtable;
482 typename A::P::uint_t data;
483
484 public:
485 objc_class_t<A> *getIsa(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(isa)); }
486
487 objc_class_data_t<A> *getData(SharedCache<A>* cache) const { return (objc_class_data_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(data)); }
488
489 objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return getData(cache)->getMethodList(cache); }
490
491 objc_protocol_list_t<A> *getProtocolList(SharedCache<A>* cache) const { return getData(cache)->getProtocolList(cache); }
492
493 objc_property_list_t<A> *getPropertyList(SharedCache<A>* cache) const { return getData(cache)->getPropertyList(cache); }
494
495 const char * getName(SharedCache<A>* cache) const {
496 return getData(cache)->getName(cache);
497 }
498
499 void setMethodList(SharedCache<A>* cache, objc_method_list_t<A>* mlist) {
500 getData(cache)->setMethodList(cache, mlist);
501 }
502
503 void setProtocolList(SharedCache<A>* cache, objc_protocol_list_t<A>* protolist) {
504 getData(cache)->setProtocolList(cache, protolist);
505 }
506
507 void setPropertyList(SharedCache<A>* cache, objc_property_list_t<A>* proplist) {
508 getData(cache)->setPropertyList(cache, proplist);
509 }
510
511 void addMethodListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
512 getData(cache)->addMethodListPointer(pointersToAdd);
513 }
514
515 void addPropertyListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
516 getData(cache)->addPropertyListPointer(pointersToAdd);
517 }
518
519 void addProtocolListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
520 getData(cache)->addProtocolListPointer(pointersToAdd);
521 }
522
523 };
524
525
526
527 template <typename A>
528 class objc_category_t {
529 typename A::P::uint_t name;
530 typename A::P::uint_t cls;
531 typename A::P::uint_t instanceMethods;
532 typename A::P::uint_t classMethods;
533 typename A::P::uint_t protocols;
534 typename A::P::uint_t instanceProperties;
535
536 public:
537
538 const char * getName(SharedCache<A> *cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
539
540 objc_class_t<A> *getClass(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(cls)); }
541
542 objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceMethods)); }
543
544 objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(classMethods)); }
545
546 objc_protocol_list_t<A> *getProtocols(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(protocols)); }
547
548 objc_property_list_t<A> *getInstanceProperties(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceProperties)); }
549
550 void getPointers(std::set<void*>& pointersToRemove) {
551 pointersToRemove.insert(&name);
552 pointersToRemove.insert(&cls);
553 pointersToRemove.insert(&instanceMethods);
554 pointersToRemove.insert(&classMethods);
555 pointersToRemove.insert(&protocols);
556 pointersToRemove.insert(&instanceProperties);
557 }
558
559
560 };
561
562 template <typename A>
563 class objc_message_ref_t {
564 typename A::P::uint_t imp;
565 typename A::P::uint_t sel;
566
567 public:
568 typename A::P::uint_t getName() const { return A::P::getP(sel); }
569
570 void setName(typename A::P::uint_t newName) { A::P::setP(sel, newName); }
571 };
572
573
574 // Call visitor.visitMethodList(mlist) on every method list in a header.
575 template <typename A, typename V>
576 class MethodListWalker {
577
578 typedef typename A::P P;
579 typedef typename A::P::uint_t pint_t;
580
581 V& mVisitor;
582
583 public:
584
585 MethodListWalker(V& visitor) : mVisitor(visitor) { }
586
587 void walk(SharedCache<A>* cache, const macho_header<P>* header)
588 {
589 // Method lists in classes
590 PointerSection<A, objc_class_t<A> *>
591 classes(cache, header, "__DATA", "__objc_classlist");
592
593 for (pint_t i = 0; i < classes.count(); i++) {
594 objc_class_t<A> *cls = classes.get(i);
595 objc_method_list_t<A> *mlist;
596 if ((mlist = cls->getMethodList(cache))) {
597 mVisitor.visitMethodList(mlist);
598 }
599 if ((mlist = cls->getIsa(cache)->getMethodList(cache))) {
600 mVisitor.visitMethodList(mlist);
601 }
602 }
603
604 // Method lists from categories
605 PointerSection<A, objc_category_t<A> *>
606 cats(cache, header, "__DATA", "__objc_catlist");
607 for (pint_t i = 0; i < cats.count(); i++) {
608 objc_category_t<A> *cat = cats.get(i);
609 objc_method_list_t<A> *mlist;
610 if ((mlist = cat->getInstanceMethods(cache))) {
611 mVisitor.visitMethodList(mlist);
612 }
613 if ((mlist = cat->getClassMethods(cache))) {
614 mVisitor.visitMethodList(mlist);
615 }
616 }
617
618 // Method description lists from protocols
619 PointerSection<A, objc_protocol_t<A> *>
620 protocols(cache, header, "__DATA", "__objc_protolist");
621 for (pint_t i = 0; i < protocols.count(); i++) {
622 objc_protocol_t<A> *proto = protocols.get(i);
623 objc_method_list_t<A> *mlist;
624 if ((mlist = proto->getInstanceMethods(cache))) {
625 mVisitor.visitMethodList(mlist);
626 }
627 if ((mlist = proto->getClassMethods(cache))) {
628 mVisitor.visitMethodList(mlist);
629 }
630 if ((mlist = proto->getOptionalInstanceMethods(cache))) {
631 mVisitor.visitMethodList(mlist);
632 }
633 if ((mlist = proto->getOptionalClassMethods(cache))) {
634 mVisitor.visitMethodList(mlist);
635 }
636 }
637 }
638 };
639
640
641 // Update selector references. The visitor performs recording and uniquing.
642 template <typename A, typename V>
643 class SelectorOptimizer {
644
645 typedef typename A::P P;
646 typedef typename A::P::uint_t pint_t;
647
648 V& mVisitor;
649
650 friend class MethodListWalker< A, SelectorOptimizer<A,V> >;
651 void visitMethodList(objc_method_list_t<A> *mlist)
652 {
653 // Gather selectors. Update method names.
654 for (pint_t m = 0; m < mlist->getCount(); m++) {
655 pint_t oldValue = mlist->get(m).getName();
656 pint_t newValue = mVisitor.visit(oldValue);
657 mlist->get(m).setName(newValue);
658 }
659 // Do not setFixedUp: the methods are not yet sorted.
660 }
661
662 public:
663
664 SelectorOptimizer(V& visitor) : mVisitor(visitor) { }
665
666 void optimize(SharedCache<A>* cache, const macho_header<P>* header)
667 {
668 // method lists of all kinds
669 MethodListWalker< A, SelectorOptimizer<A,V> > mw(*this);
670 mw.walk(cache, header);
671
672 // @selector references
673 PointerSection<A, const char *>
674 selrefs(cache, header, "__DATA", "__objc_selrefs");
675 for (pint_t i = 0; i < selrefs.count(); i++) {
676 pint_t oldValue = selrefs.getUnmapped(i);
677 pint_t newValue = mVisitor.visit(oldValue);
678 selrefs.set(i, newValue);
679 }
680
681 // message references
682 ArraySection<A, objc_message_ref_t<A> >
683 msgrefs(cache, header, "__DATA", "__objc_msgrefs");
684 for (pint_t i = 0; i < msgrefs.count(); i++) {
685 objc_message_ref_t<A>& msg = msgrefs.get(i);
686 pint_t oldValue = msg.getName();
687 pint_t newValue = mVisitor.visit(oldValue);
688 msg.setName(newValue);
689 }
690
691 // Mark image_info
692 const macho_section<P> *imageInfoSection =
693 header->getSection("__DATA", "__objc_imageinfo");
694 if (imageInfoSection) {
695 objc_image_info<A> *info = (objc_image_info<A> *)
696 cache->mappedAddressForVMAddress(imageInfoSection->addr());
697 info->setSelectorsPrebound();
698 }
699 }
700 };
701
702
703 // Sort methods in place by selector.
704 template <typename A>
705 class MethodListSorter {
706
707 typedef typename A::P P;
708 typedef typename A::P::uint_t pint_t;
709
710 friend class MethodListWalker<A, MethodListSorter<A> >;
711 void visitMethodList(objc_method_list_t<A> *mlist)
712 {
713 typename objc_method_t<A>::SortBySELAddress sorter;
714 std::stable_sort(mlist->begin(), mlist->end(), sorter);
715 mlist->setFixedUp();
716 }
717
718 public:
719
720 void optimize(SharedCache<A>* cache, macho_header<P>* header)
721 {
722 MethodListWalker<A, MethodListSorter<A> > mw(*this);
723 mw.walk(cache, header);
724 }
725 };
726
727
728 // Attach categories to classes in the same framework.
729 // Merge method and protocol and property lists.
730 template <typename A>
731 class CategoryAttacher {
732
733 typedef typename A::P P;
734 typedef typename A::P::uint_t pint_t;
735
736 uint8_t *mBytes;
737 ssize_t mBytesFree;
738 ssize_t mBytesUsed;
739
740 size_t mCategoriesAttached;
741
742 bool segmentContainsPointer(SharedCache<A>* cache,
743 const macho_segment_command<P>* seg, void *ptr)
744 {
745 if (!seg) return false;
746 void *start = (void*)
747 cache->mappedAddressForVMAddress(seg->vmaddr());
748 void *end = (uint8_t *)start + seg->filesize();
749 return (ptr >= start && ptr < end);
750 }
751
752 bool headerContainsPointer(SharedCache<A>* cache,
753 macho_header<P>* header, void *ptr)
754 {
755 return
756 segmentContainsPointer(cache, header->getSegment("__DATA"), ptr) ||
757 segmentContainsPointer(cache, header->getSegment("__TEXT"), ptr) ||
758 segmentContainsPointer(cache, header->getSegment("__OBJC"), ptr);
759 }
760
761 struct pointer_hash {
762 size_t operator () (void* ptr) const {
763 return __gnu_cxx::hash<long>()((long)ptr);
764 }
765 };
766
767 typedef std::deque<objc_category_t<A>*> CategoryList;
768 typedef std::vector<uint64_t> CategoryRefs;
769
770 struct ClassChanges {
771 CategoryList categories;
772 CategoryRefs catrefs;
773
774 objc_method_list_t<A>* instanceMethods;
775 objc_method_list_t<A>* classMethods;
776 objc_protocol_list_t<A>* protocols;
777 objc_property_list_t<A>* instanceProperties;
778
779 ClassChanges()
780 : instanceMethods(NULL), classMethods(NULL),
781 protocols(NULL), instanceProperties(NULL)
782 { }
783
784 ~ClassChanges() {
785 if (instanceMethods) delete instanceMethods;
786 if (classMethods) delete classMethods;
787 if (protocols) delete protocols;
788 if (instanceProperties) delete instanceProperties;
789 }
790 };
791
792 typedef __gnu_cxx::hash_map<objc_class_t<A>*, ClassChanges, pointer_hash> ClassMap;
793
794 class RangeArray {
795 typedef std::pair<uint8_t*,uint32_t> Range;
796 std::deque<Range> ranges;
797
798 class SizeFits {
799 private:
800 uint32_t mSize;
801 public:
802 SizeFits(uint32_t size) : mSize(size) { }
803 bool operator() (const Range& r) {
804 return r.second >= mSize;
805 }
806 };
807
808 struct AddressComp {
809 bool operator() (const Range& lhs, const Range& rhs) {
810 return (lhs.first < rhs.first);
811 }
812 };
813 public:
814 RangeArray() { }
815 void add(void* p, uint32_t size) {
816 add(Range((uint8_t *)p, size));
817 }
818 void add(const Range& r) {
819 // find insertion point
820 std::deque<Range>::iterator iter;
821 iter = upper_bound(ranges.begin(), ranges.end(), r, AddressComp());
822 // coalesce
823 // fixme doesn't fully coalesce if new range exactly fills a gap
824 if (iter != ranges.begin()) {
825 std::deque<Range>::iterator prev = iter - 1;
826 if ((*prev).first + (*prev).second == r.first) {
827 (*prev).second += r.second;
828 return;
829 }
830 }
831 if (iter != ranges.end() && iter+1 != ranges.end()) {
832 std::deque<Range>::iterator next = iter + 1;
833 if (r.first + r.second == (*next).first) {
834 (*next).second += r.second;
835 (*next).first = r.first;
836 return;
837 }
838 }
839 ranges.insert(iter, r);
840 }
841
842 uint8_t* remove(uint32_t size) {
843 // first-fit search
844 // this saves 50-75% of space overhead;
845 // a better algorithm might do better
846
847 std::deque<Range>::iterator iter;
848 iter = find_if(ranges.begin(), ranges.end(), SizeFits(size));
849 if (iter == ranges.end()) {
850 return NULL;
851 }
852
853 Range& found = *iter;
854 uint8_t *result = found.first;
855 if (found.second > size) {
856 // keep leftovers
857 found.first += size;
858 found.second -= size;
859 } else {
860 ranges.erase(iter);
861 }
862
863 return result;
864 }
865 };
866
867 void copyMethods(typename objc_method_list_t<A>::method_iterator& dst,
868 const objc_method_list_t<A>* srcList)
869 {
870 objc_method_list_t<A>::method_iterator::
871 overwrite(dst, srcList);
872 }
873
874 void copyProperties(typename objc_property_list_t<A>::property_iterator& dst,
875 const objc_property_list_t<A>* srcList)
876 {
877 objc_property_list_t<A>::property_iterator::
878 overwrite(dst, srcList);
879 }
880
881 void copyProtocols(objc_protocol_list_t<A>* dst, pint_t& dstIndex,
882 const objc_protocol_list_t<A>* src)
883 {
884 dst->overwrite(dstIndex, src);
885 }
886
887 class InSet
888 {
889 public:
890 InSet(std::set<void*>& deadPointers) : _deadPointers(deadPointers) {}
891
892 bool operator()(void* ptr) const {
893 return ( _deadPointers.count(ptr) != 0 );
894 }
895
896 private:
897 std::set<void*>& _deadPointers;
898 };
899
900 public:
901
902 CategoryAttacher(uint8_t *bytes, ssize_t bytesFree)
903 : mBytes(bytes), mBytesFree(bytesFree)
904 , mBytesUsed(0), mCategoriesAttached(0)
905 { }
906
907 size_t count() const { return mCategoriesAttached; }
908
909 const char *optimize(SharedCache<A>* cache, macho_header<P>* header, std::vector<void*>& pointersInData)
910 {
911 // Build class=>cateories mapping.
912 // Disregard target classes that aren't in this binary.
913
914 ClassMap map;
915
916 PointerSection<A, objc_category_t<A> *>
917 nlcatsect(cache, header, "__DATA", "__objc_nlcatlist");
918 PointerSection<A, objc_category_t<A> *>
919 catsect(cache, header, "__DATA", "__objc_catlist");
920 for (pint_t i = 0; i < catsect.count(); i++) {
921 objc_category_t<A> *cat = catsect.get(i);
922 objc_class_t<A> *cls = cat->getClass(cache);
923 if (!cls) continue;
924 if (!headerContainsPointer(cache, header, cls)) continue;
925 if ( nlcatsect.count() !=0 ) {
926 // don't optimize categories also in __objc_nlcatlist
927 bool alsoInNlcatlist = false;
928 for (pint_t nli = 0; nli < nlcatsect.count(); nli++) {
929 if ( nlcatsect.get(nli) == cat ) {
930 //fprintf(stderr, "skipping cat in __objc_nlcatlist for mh=%p\n", header);
931 alsoInNlcatlist = true;
932 break;
933 }
934 }
935 if ( alsoInNlcatlist )
936 continue;
937 }
938
939 // The LAST category found is the FIRST to be processed later.
940 map[cls].categories.push_front(cat);
941
942 // We don't care about the category reference order.
943 map[cls].catrefs.push_back(i);
944 }
945
946 if (map.size() == 0) {
947 // No attachable categories.
948 return NULL;
949 }
950
951 // Process each class.
952 // Each class is all-or-nothing: either all of its categories
953 // are attached successfully, or none of them are. This preserves
954 // cache validity if we run out of space for more reallocations.
955
956 // unusedMemory stores memory ranges evacuated by now-unused metadata.
957 // It is available for re-use by other newly-added metadata.
958 // fixme could packing algorithm be improved?
959 RangeArray unusedMemory;
960
961 ssize_t reserve = 0;
962
963 // First: build new aggregated lists on the heap.
964 // Require enough space in mBytes for all of it.
965
966 std::set<void*> pointersToRemove;
967 for (typename ClassMap::iterator i = map.begin();
968 i != map.end();
969 ++i)
970 {
971 objc_class_t<A>* cls = i->first;
972 objc_class_t<A>* meta = cls->getIsa(cache);
973 ClassChanges& changes = i->second;
974 CategoryList& cats = changes.categories;
975
976 // Count memory needed for all categories on this class.
977
978 uint32_t methodEntsize = 0;
979 uint32_t propertyEntsize = 0;
980 objc_method_list_t<A>* mlist;
981 objc_property_list_t<A>* proplist;
982 objc_protocol_list_t<A>* protolist;
983 uint32_t instanceMethodsCount = 0;
984 uint32_t classMethodsCount = 0;
985 uint32_t instancePropertyCount = 0;
986 pint_t protocolCount = 0;
987 bool addedInstanceMethods = false;
988 bool addedClassMethods = false;
989 bool addedInstanceProperties = false;
990 bool addedProtocols = false;
991
992 mlist = cls->getMethodList(cache);
993 if (mlist) {
994 instanceMethodsCount = mlist->getCount();
995 methodEntsize =
996 std::max(methodEntsize, mlist->getEntsize());
997 }
998
999 mlist = meta->getMethodList(cache);
1000 if (mlist) {
1001 classMethodsCount = mlist->getCount();
1002 methodEntsize =
1003 std::max(methodEntsize, mlist->getEntsize());
1004 }
1005
1006 proplist = cls->getPropertyList(cache);
1007 if (proplist) {
1008 instancePropertyCount = proplist->getCount();
1009 propertyEntsize =
1010 std::max(propertyEntsize, proplist->getEntsize());
1011 }
1012
1013 protolist = cls->getProtocolList(cache);
1014 if (protolist) {
1015 protocolCount = protolist->getCount();
1016 }
1017
1018 typename CategoryList::iterator j;
1019 for (j = cats.begin(); j != cats.end(); ++j) {
1020 objc_category_t<A>* cat = *j;
1021
1022 mlist = cat->getInstanceMethods(cache);
1023 if (mlist && mlist->getCount() > 0) {
1024 addedInstanceMethods = true;
1025 instanceMethodsCount += mlist->getCount();
1026 methodEntsize =
1027 std::max(methodEntsize, mlist->getEntsize());
1028 }
1029
1030 mlist = cat->getClassMethods(cache);
1031 if (mlist && mlist->getCount() > 0) {
1032 addedClassMethods = true;
1033 classMethodsCount += mlist->getCount();
1034 methodEntsize =
1035 std::max(methodEntsize, mlist->getEntsize());
1036 }
1037
1038 proplist = cat->getInstanceProperties(cache);
1039 if (proplist && proplist->getCount() > 0) {
1040 addedInstanceProperties = true;
1041 instancePropertyCount += proplist->getCount();
1042 propertyEntsize =
1043 std::max(propertyEntsize, proplist->getEntsize());
1044 }
1045
1046 protolist = cat->getProtocols(cache);
1047 if (protolist && protolist->getCount() > 0) {
1048 addedProtocols = true;
1049 protocolCount += protolist->getCount();
1050 }
1051 }
1052
1053 // Allocate memory for aggregated lists.
1054 // Reserve the same amount of space from mBytes.
1055
1056 if (addedInstanceMethods) {
1057 changes.instanceMethods = objc_method_list_t<A>::newMethodList(instanceMethodsCount, methodEntsize);
1058 reserve = P::round_up(reserve + changes.instanceMethods->byteSize());
1059 }
1060 if (addedClassMethods) {
1061 changes.classMethods = objc_method_list_t<A>::newMethodList(classMethodsCount, methodEntsize);
1062 reserve = P::round_up(reserve + changes.classMethods->byteSize());
1063 }
1064 if (addedInstanceProperties) {
1065 changes.instanceProperties = objc_property_list_t<A>::newPropertyList(instancePropertyCount, propertyEntsize);
1066 reserve = P::round_up(reserve + changes.instanceProperties->byteSize());
1067 }
1068 if (addedProtocols) {
1069 changes.protocols = objc_protocol_list_t<A>::newProtocolList(protocolCount);
1070 reserve = P::round_up(reserve + changes.protocols->byteSize());
1071 }
1072
1073 // Merge. The LAST category's contents ends up FIRST in each list.
1074 // The aggregated lists are not sorted; a future pass does that.
1075
1076 typename objc_method_list_t<A>::method_iterator newInstanceMethods;
1077 typename objc_method_list_t<A>::method_iterator newClassMethods;
1078 typename objc_property_list_t<A>::property_iterator newInstanceProperties;
1079 pint_t newProtocolIndex;
1080
1081 if (addedInstanceMethods) {
1082 newInstanceMethods = changes.instanceMethods->begin();
1083 }
1084 if (addedClassMethods) {
1085 newClassMethods = changes.classMethods->begin();
1086 }
1087 if (addedInstanceProperties) {
1088 newInstanceProperties = changes.instanceProperties->begin();
1089 }
1090 if (addedProtocols) {
1091 newProtocolIndex = 0;
1092 }
1093
1094 for (j = cats.begin(); j != cats.end(); ++j) {
1095 objc_category_t<A>* cat = *j;
1096
1097 mlist = cat->getInstanceMethods(cache);
1098 if (mlist) {
1099 copyMethods(newInstanceMethods, mlist);
1100 mlist->getPointers(pointersToRemove);
1101 unusedMemory.add(mlist, mlist->byteSize());
1102 }
1103
1104 mlist = cat->getClassMethods(cache);
1105 if (mlist) {
1106 copyMethods(newClassMethods, mlist);
1107 mlist->getPointers(pointersToRemove);
1108 unusedMemory.add(mlist, mlist->byteSize());
1109 }
1110
1111 proplist = cat->getInstanceProperties(cache);
1112 if (proplist) {
1113 copyProperties(newInstanceProperties, proplist);
1114 proplist->getPointers(pointersToRemove);
1115 unusedMemory.add(proplist, proplist->byteSize());
1116 }
1117
1118 protolist = cat->getProtocols(cache);
1119 if (protolist) {
1120 copyProtocols(changes.protocols, newProtocolIndex, protolist);
1121 protolist->getPointers(pointersToRemove);
1122 unusedMemory.add(protolist, protolist->byteSize());
1123 }
1124
1125 cat->getPointers(pointersToRemove);
1126 unusedMemory.add(cat, sizeof(*cat));
1127 }
1128
1129 if (addedInstanceMethods && (mlist = cls->getMethodList(cache))) {
1130 copyMethods(newInstanceMethods, mlist);
1131 mlist->getPointers(pointersToRemove);
1132 unusedMemory.add(mlist, mlist->byteSize());
1133 }
1134 if (addedClassMethods && (mlist = meta->getMethodList(cache))) {
1135 copyMethods(newClassMethods, mlist);
1136 mlist->getPointers(pointersToRemove);
1137 unusedMemory.add(mlist, mlist->byteSize());
1138 }
1139 if (addedInstanceProperties && (proplist = cls->getPropertyList(cache))) {
1140 copyProperties(newInstanceProperties, proplist);
1141 proplist->getPointers(pointersToRemove);
1142 unusedMemory.add(proplist, proplist->byteSize());
1143 }
1144 if (addedProtocols && (protolist = cls->getProtocolList(cache))) {
1145 copyProtocols(changes.protocols, newProtocolIndex, protolist);
1146 protolist->getPointers(pointersToRemove);
1147 unusedMemory.add(protolist, protolist->byteSize());
1148 }
1149 }
1150
1151 if (reserve > mBytesFree) {
1152 return "insufficient space for category data (metadata not optimized)";
1153 }
1154
1155 // update cache slide info and remove areas now longer containing pointers
1156 //fprintf(stderr, "found %lu pointers in objc structures being moved\n", pointersToRemove.size());
1157 pointersInData.erase(std::remove_if(pointersInData.begin(), pointersInData.end(), InSet(pointersToRemove)), pointersInData.end());
1158
1159
1160 // All lists are now built.
1161 // mBytes is big enough to hold everything if necessary.
1162 // Everything in unusedMemory is now available for re-use.
1163 // The original metadata is still untouched.
1164
1165 // Second: write lists into mBytes and unusedMemory,
1166 // then disconnect categories.
1167
1168 for (typename ClassMap::iterator i = map.begin();
1169 i != map.end();
1170 ++i)
1171 {
1172 objc_class_t<A>* cls = i->first;
1173 objc_class_t<A>* meta = cls->getIsa(cache);
1174 ClassChanges& changes = i->second;
1175
1176 // Write lists.
1177
1178 if (changes.instanceMethods) {
1179 uint8_t *bytes;
1180 uint32_t size = changes.instanceMethods->byteSize();
1181 if (! (bytes = unusedMemory.remove(size))) {
1182 bytes = mBytes + mBytesUsed;
1183 mBytesFree -= size;
1184 mBytesUsed += size;
1185 }
1186 memcpy(bytes, changes.instanceMethods, size);
1187 objc_method_list_t<A>::addPointers(bytes, pointersInData);
1188 cls->setMethodList(cache, (objc_method_list_t<A> *)bytes);
1189 cls->addMethodListPointer(cache, pointersInData);
1190 }
1191
1192 if (changes.classMethods) {
1193 uint8_t *bytes;
1194 uint32_t size = changes.classMethods->byteSize();
1195 if (! (bytes = unusedMemory.remove(size))) {
1196 bytes = mBytes + mBytesUsed;
1197 mBytesFree -= size;
1198 mBytesUsed += size;
1199 }
1200 memcpy(bytes, changes.classMethods, size);
1201 objc_method_list_t<A>::addPointers(bytes, pointersInData);
1202 meta->setMethodList(cache, (objc_method_list_t<A> *)bytes);
1203 meta->addMethodListPointer(cache, pointersInData);
1204 }
1205
1206 if (changes.instanceProperties) {
1207 uint8_t *bytes;
1208 uint32_t size = changes.instanceProperties->byteSize();
1209 if (! (bytes = unusedMemory.remove(size))) {
1210 bytes = mBytes + mBytesUsed;
1211 mBytesFree -= size;
1212 mBytesUsed += size;
1213 }
1214 memcpy(bytes, changes.instanceProperties, size);
1215 objc_property_list_t<A>::addPointers(bytes, pointersInData);
1216 cls->setPropertyList(cache, (objc_property_list_t<A> *)bytes);
1217 cls->addPropertyListPointer(cache, pointersInData);
1218 }
1219
1220 if (changes.protocols) {
1221 uint8_t *bytes;
1222 uint32_t size = changes.protocols->byteSize();
1223 if (! (bytes = unusedMemory.remove(size))) {
1224 bytes = mBytes + mBytesUsed;
1225 mBytesFree -= size;
1226 mBytesUsed += size;
1227 }
1228 memcpy(bytes, changes.protocols, size);
1229 cls->setProtocolList(cache, (objc_protocol_list_t<A> *)bytes);
1230 objc_protocol_list_t<A>::addPointers(bytes, pointersInData);
1231 cls->addProtocolListPointer(cache, pointersInData);
1232 meta->setProtocolList(cache, (objc_protocol_list_t<A> *)bytes);
1233 meta->addProtocolListPointer(cache, pointersInData);
1234 }
1235
1236 // Disavow all knowledge of the categories.
1237
1238 for (typename CategoryRefs::iterator j = changes.catrefs.begin();
1239 j != changes.catrefs.end();
1240 ++j)
1241 {
1242 catsect.set(*j, 0);
1243 }
1244
1245 mCategoriesAttached += changes.categories.size();
1246 }
1247
1248 catsect.removeNulls();
1249
1250 return NULL;
1251 }
1252
1253 ssize_t bytesUsed() { return mBytesUsed; }
1254 };