1/* 2 * Copyright (C) 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import <objc/runtime.h> 27#import <wtf/HashSet.h> 28#import <wtf/Vector.h> 29 30inline bool protocolImplementsProtocol(Protocol *candidate, Protocol *target) 31{ 32 unsigned protocolProtocolsCount; 33 Protocol ** protocolProtocols = protocol_copyProtocolList(candidate, &protocolProtocolsCount); 34 for (unsigned i = 0; i < protocolProtocolsCount; ++i) { 35 if (protocol_isEqual(protocolProtocols[i], target)) { 36 free(protocolProtocols); 37 return true; 38 } 39 } 40 free(protocolProtocols); 41 return false; 42} 43 44inline void forEachProtocolImplementingProtocol(Class cls, Protocol *target, void (^callback)(Protocol *)) 45{ 46 ASSERT(cls); 47 ASSERT(target); 48 49 Vector<Protocol *> worklist; 50 HashSet<void*> visited; 51 52 // Initially fill the worklist with the Class's protocols. 53 unsigned protocolsCount; 54 Protocol ** protocols = class_copyProtocolList(cls, &protocolsCount); 55 worklist.append(protocols, protocolsCount); 56 free(protocols); 57 58 while (!worklist.isEmpty()) { 59 Protocol *protocol = worklist.last(); 60 worklist.removeLast(); 61 62 // Are we encountering this Protocol for the first time? 63 if (!visited.add(protocol).isNewEntry) 64 continue; 65 66 // If it implements the protocol, make the callback. 67 if (protocolImplementsProtocol(protocol, target)) 68 callback(protocol); 69 70 // Add incorporated protocols to the worklist. 71 protocols = protocol_copyProtocolList(protocol, &protocolsCount); 72 worklist.append(protocols, protocolsCount); 73 free(protocols); 74 } 75} 76 77inline void forEachMethodInClass(Class cls, void (^callback)(Method)) 78{ 79 unsigned count; 80 Method* methods = class_copyMethodList(cls, &count); 81 for (unsigned i = 0; i < count; ++i) 82 callback(methods[i]); 83 free(methods); 84} 85 86inline void forEachMethodInProtocol(Protocol *protocol, BOOL isRequiredMethod, BOOL isInstanceMethod, void (^callback)(SEL, const char*)) 87{ 88 unsigned count; 89 struct objc_method_description* methods = protocol_copyMethodDescriptionList(protocol, isRequiredMethod, isInstanceMethod, &count); 90 for (unsigned i = 0; i < count; ++i) 91 callback(methods[i].name, methods[i].types); 92 free(methods); 93} 94 95inline void forEachPropertyInProtocol(Protocol *protocol, void (^callback)(objc_property_t)) 96{ 97 unsigned count; 98 objc_property_t* properties = protocol_copyPropertyList(protocol, &count); 99 for (unsigned i = 0; i < count; ++i) 100 callback(properties[i]); 101 free(properties); 102} 103 104template<char open, char close> 105void skipPair(const char*& position) 106{ 107 size_t count = 1; 108 do { 109 char c = *position++; 110 if (!c) 111 @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Malformed type encoding" userInfo:nil]; 112 if (c == open) 113 ++count; 114 else if (c == close) 115 --count; 116 } while (count); 117} 118 119class StringRange { 120 WTF_MAKE_NONCOPYABLE(StringRange); 121public: 122 StringRange(const char* begin, const char* end) : m_ptr(strndup(begin, end - begin)) { } 123 ~StringRange() { free(m_ptr); } 124 operator const char*() const { return m_ptr; } 125 const char* get() const { return m_ptr; } 126 127private: 128 char* m_ptr; 129}; 130 131class StructBuffer { 132 WTF_MAKE_NONCOPYABLE(StructBuffer); 133public: 134 StructBuffer(const char* encodedType) 135 { 136 NSUInteger size, alignment; 137 NSGetSizeAndAlignment(encodedType, &size, &alignment); 138 --alignment; 139 m_allocation = static_cast<char*>(malloc(size + alignment)); 140 m_buffer = reinterpret_cast<char*>((reinterpret_cast<intptr_t>(m_allocation) + alignment) & ~alignment); 141 } 142 143 ~StructBuffer() { free(m_allocation); } 144 operator void*() const { return m_buffer; } 145 146private: 147 void* m_allocation; 148 void* m_buffer; 149}; 150 151template<typename DelegateType> 152typename DelegateType::ResultType parseObjCType(const char*& position) 153{ 154 ASSERT(*position); 155 156 switch (*position++) { 157 case 'c': 158 return DelegateType::template typeInteger<char>(); 159 case 'i': 160 return DelegateType::template typeInteger<int>(); 161 case 's': 162 return DelegateType::template typeInteger<short>(); 163 case 'l': 164 return DelegateType::template typeInteger<long>(); 165 case 'q': 166 return DelegateType::template typeDouble<unsigned long long>(); 167 case 'C': 168 return DelegateType::template typeInteger<unsigned char>(); 169 case 'I': 170 return DelegateType::template typeInteger<unsigned>(); 171 case 'S': 172 return DelegateType::template typeInteger<unsigned short>(); 173 case 'L': 174 return DelegateType::template typeInteger<unsigned long>(); 175 case 'Q': 176 return DelegateType::template typeDouble<unsigned long long>(); 177 case 'f': 178 return DelegateType::template typeDouble<float>(); 179 case 'd': 180 return DelegateType::template typeDouble<double>(); 181 case 'B': 182 return DelegateType::typeBool(); 183 case 'v': 184 return DelegateType::typeVoid(); 185 186 case '@': { // An object (whether statically typed or typed id) 187 if (position[0] == '?' && position[1] == '<') { 188 position += 2; 189 const char* begin = position; 190 skipPair<'<','>'>(position); 191 return DelegateType::typeBlock(begin, position - 1); 192 } 193 194 if (*position == '"') { 195 const char* begin = ++position; 196 position = index(position, '"'); 197 return DelegateType::typeOfClass(begin, position++); 198 } 199 200 return DelegateType::typeId(); 201 } 202 203 case '{': { // {name=type...} A structure 204 const char* begin = position - 1; 205 skipPair<'{','}'>(position); 206 return DelegateType::typeStruct(begin, position); 207 } 208 209 // NOT supporting C strings, arrays, pointers, unions, bitfields, function pointers. 210 case '*': // A character string (char *) 211 case '[': // [array type] An array 212 case '(': // (name=type...) A union 213 case 'b': // bnum A bit field of num bits 214 case '^': // ^type A pointer to type 215 case '?': // An unknown type (among other things, this code is used for function pointers) 216 // NOT supporting Objective-C Class, SEL 217 case '#': // A class object (Class) 218 case ':': // A method selector (SEL) 219 default: 220 return nil; 221 } 222} 223 224extern "C" { 225 // Forward declare some Objective-C runtime internal methods that are not API. 226 const char *_protocol_getMethodTypeEncoding(Protocol *, SEL, BOOL isRequiredMethod, BOOL isInstanceMethod); 227 id objc_initWeak(id *, id); 228 void objc_destroyWeak(id *); 229 bool _Block_has_signature(void *); 230 const char * _Block_signature(void *); 231} 232