ObjCModernAbstraction.hpp [plain text]
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
* Copyright (c) 2008 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
template <typename A>
class objc_method_t {
typename A::P::uint_t name; // SEL
typename A::P::uint_t types; // const char *
typename A::P::uint_t imp; // IMP
public:
typename A::P::uint_t getName() const { return A::P::getP(name); }
void setName(typename A::P::uint_t newName) { A::P::setP(name, newName); }
};
template <typename A>
class objc_method_list_t {
uint32_t entsize;
uint32_t count;
objc_method_t<A> first;
uint32_t getEntsize() const { return A::P::E::get32(entsize) & ~(uint32_t)3; }
public:
typename A::P::uint_t getCount() const { return A::P::E::get32(count); }
objc_method_t<A>& get(typename A::P::uint_t i) const { return *(objc_method_t<A> *)((uint8_t *)&first + i * getEntsize()); }
void setFixedUp() { A::P::E::set32(entsize, getEntsize() | 3); }
};
template <typename A>
class objc_ivar_t {
typename A::P::uint_t offset; // A::P *
typename A::P::uint_t name; // const char *
typename A::P::uint_t type; // const char *
uint32_t alignment;
uint32_t size;
};
template <typename A>
class objc_ivar_list_t {
uint32_t entsize;
uint32_t count;
objc_ivar_t<A> first;
public:
objc_ivar_t<A>& getIvarAtIndex(typename A::P::pint_t i) const { return *(objc_ivar_t<A> *)((uint8_t *)&first + i * A::P::E::get32(entsize)); }
};
template <typename A>
class objc_protocol_t {
typename A::P::uint_t isa;
typename A::P::uint_t name;
typename A::P::uint_t protocols;
typename A::P::uint_t instanceMethods;
typename A::P::uint_t classMethods;
typename A::P::uint_t optionalInstanceMethods;
typename A::P::uint_t optionalClassMethods;
typename A::P::uint_t instanceProperties;
public:
objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(instanceMethods)); }
objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(classMethods)); }
objc_method_list_t<A> *getOptionalInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(optionalInstanceMethods)); }
objc_method_list_t<A> *getOptionalClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(optionalClassMethods)); }
};
template <typename A>
class objc_protocol_list_t {
typename A::P::uint_t count;
typename A::P::uint_t list[0];
};
template < typename P, typename E >
struct pad { };
template < typename E >
struct pad< Pointer64<E>, E > { uint32_t unused; };
template <typename A>
class objc_class_data_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
pad<typename A::P, typename A::P::E> reserved; // ILP32=0 bytes, LP64=4 bytes
typename A::P::uint_t ivarLayout;
typename A::P::uint_t name;
typename A::P::uint_t baseMethods;
typename A::P::uint_t baseProtocols;
typename A::P::uint_t ivars;
typename A::P::uint_t weakIvarLayout;
typename A::P::uint_t baseProperties;
public:
objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(baseMethods)); }
};
template <typename A>
class objc_class_t {
typename A::P::uint_t isa;
typename A::P::uint_t superclass;
typename A::P::uint_t method_cache;
typename A::P::uint_t vtable;
typename A::P::uint_t data;
public:
objc_class_t<A> *getIsa(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(isa)); }
objc_class_data_t<A> *getData(SharedCache<A>* cache) const { return (objc_class_data_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(data)); }
objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return getData(cache)->getMethodList(cache); }
};
template <typename A>
class objc_category_t {
typename A::P::uint_t name;
typename A::P::uint_t cls;
typename A::P::uint_t instanceMethods;
typename A::P::uint_t classMethods;
typename A::P::uint_t protocols;
typename A::P::uint_t instanceProperties;
public:
objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(instanceMethods)); }
objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(classMethods)); }
};
template <typename A>
class objc_message_ref_t {
typename A::P::uint_t imp;
typename A::P::uint_t sel;
public:
typename A::P::uint_t getName() const { return A::P::getP(sel); }
void setName(typename A::P::uint_t newName) { A::P::setP(sel, newName); }
};
template <typename A, typename V>
class SelectorUpdater {
typedef typename A::P P;
typedef typename A::P::uint_t pint_t;
static void visitMethodList(objc_method_list_t<A> *mlist, V& visitor)
{
for (pint_t m = 0; m < mlist->getCount(); m++) {
pint_t oldValue = mlist->get(m).getName();
pint_t newValue = visitor.visit(oldValue);
mlist->get(m).setName(newValue);
}
mlist->setFixedUp();
}
public:
static void update(SharedCache<A>* cache, const macho_header<P>* header,
V& visitor)
{
// Method lists in classes
PointerSection<A, objc_class_t<A> *>
classes(cache, header, "__DATA", "__objc_classlist");
for (pint_t i = 0; i < classes.count(); i++) {
objc_class_t<A> *cls = classes.get(i);
objc_method_list_t<A> *mlist;
if ((mlist = cls->getMethodList(cache))) {
visitMethodList(mlist, visitor);
}
if ((mlist = cls->getIsa(cache)->getMethodList(cache))) {
visitMethodList(mlist, visitor);
}
}
// Method lists from categories
PointerSection<A, objc_category_t<A> *>
cats(cache, header, "__DATA", "__objc_catlist");
for (pint_t i = 0; i < cats.count(); i++) {
objc_category_t<A> *cat = cats.get(i);
objc_method_list_t<A> *mlist;
if ((mlist = cat->getInstanceMethods(cache))) {
visitMethodList(mlist, visitor);
}
if ((mlist = cat->getClassMethods(cache))) {
visitMethodList(mlist, visitor);
}
}
// Method description lists from protocols
PointerSection<A, objc_protocol_t<A> *>
protocols(cache, header, "__DATA", "__objc_protolist");
for (pint_t i = 0; i < protocols.count(); i++) {
objc_protocol_t<A> *proto = protocols.get(i);
objc_method_list_t<A> *mlist;
if ((mlist = proto->getInstanceMethods(cache))) {
visitMethodList(mlist, visitor);
}
if ((mlist = proto->getClassMethods(cache))) {
visitMethodList(mlist, visitor);
}
if ((mlist = proto->getOptionalInstanceMethods(cache))) {
visitMethodList(mlist, visitor);
}
if ((mlist = proto->getOptionalClassMethods(cache))) {
visitMethodList(mlist, visitor);
}
}
// @selector references
PointerSection<A, const char *>
selrefs(cache, header, "__DATA", "__objc_selrefs");
for (pint_t i = 0; i < selrefs.count(); i++) {
pint_t oldValue = selrefs.getUnmapped(i);
pint_t newValue = visitor.visit(oldValue);
selrefs.set(i, newValue);
}
// message references
ArraySection<A, objc_message_ref_t<A> >
msgrefs(cache, header, "__DATA", "__objc_msgrefs");
for (pint_t i = 0; i < msgrefs.count(); i++) {
objc_message_ref_t<A>& msg = msgrefs.get(i);
pint_t oldValue = msg.getName();
pint_t newValue = visitor.visit(oldValue);
msg.setName(newValue);
}
// Mark image_info
const macho_section<P> *imageInfoSection =
header->getSection("__DATA", "__objc_imageinfo");
if (imageInfoSection) {
objc_image_info<A> *info = (objc_image_info<A> *)
cache->mappedCacheAddressForAddress(imageInfoSection->addr());
info->setSelectorsPrebound();
}
}
};