ObjcRuntimeExtras.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*
  2. * Copyright (C) 2013, 2017 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. #import <memory>
  26. #import <objc/Protocol.h>
  27. #import <objc/runtime.h>
  28. #import <wtf/HashSet.h>
  29. #import <wtf/SystemFree.h>
  30. #import <wtf/Vector.h>
  31. #import <wtf/text/CString.h>
  32. template<typename T, typename U>
  33. inline std::unique_ptr<T, WTF::SystemFree<T>> adoptSystem(U value)
  34. {
  35. return std::unique_ptr<T, WTF::SystemFree<T>>(value);
  36. }
  37. inline bool protocolImplementsProtocol(Protocol *candidate, Protocol *target)
  38. {
  39. unsigned protocolProtocolsCount;
  40. auto protocolProtocols = adoptSystem<__unsafe_unretained Protocol*[]>(protocol_copyProtocolList(candidate, &protocolProtocolsCount));
  41. for (unsigned i = 0; i < protocolProtocolsCount; ++i) {
  42. if (protocol_isEqual(protocolProtocols[i], target))
  43. return true;
  44. }
  45. return false;
  46. }
  47. inline void forEachProtocolImplementingProtocol(Class cls, Protocol *target, void (^callback)(Protocol *, bool& stop))
  48. {
  49. ASSERT(cls);
  50. ASSERT(target);
  51. Vector<Protocol*> worklist;
  52. HashSet<void*> visited;
  53. // Initially fill the worklist with the Class's protocols.
  54. {
  55. unsigned protocolsCount;
  56. auto protocols = adoptSystem<__unsafe_unretained Protocol*[]>(class_copyProtocolList(cls, &protocolsCount));
  57. worklist.append(protocols.get(), protocolsCount);
  58. }
  59. bool stop = false;
  60. while (!worklist.isEmpty()) {
  61. Protocol *protocol = worklist.last();
  62. worklist.removeLast();
  63. // Are we encountering this Protocol for the first time?
  64. if (!visited.add((__bridge void*)protocol).isNewEntry)
  65. continue;
  66. // If it implements the protocol, make the callback.
  67. if (protocolImplementsProtocol(protocol, target)) {
  68. callback(protocol, stop);
  69. if (stop)
  70. break;
  71. }
  72. // Add incorporated protocols to the worklist.
  73. {
  74. unsigned protocolsCount;
  75. auto protocols = adoptSystem<__unsafe_unretained Protocol*[]>(protocol_copyProtocolList(protocol, &protocolsCount));
  76. worklist.append(protocols.get(), protocolsCount);
  77. }
  78. }
  79. }
  80. inline void forEachMethodInClass(Class cls, void (^callback)(Method))
  81. {
  82. unsigned count;
  83. auto methods = adoptSystem<Method[]>(class_copyMethodList(cls, &count));
  84. for (unsigned i = 0; i < count; ++i)
  85. callback(methods[i]);
  86. }
  87. inline void forEachMethodInProtocol(Protocol *protocol, BOOL isRequiredMethod, BOOL isInstanceMethod, void (^callback)(SEL, const char*))
  88. {
  89. unsigned count;
  90. auto methods = adoptSystem<objc_method_description[]>(protocol_copyMethodDescriptionList(protocol, isRequiredMethod, isInstanceMethod, &count));
  91. for (unsigned i = 0; i < count; ++i)
  92. callback(methods[i].name, methods[i].types);
  93. }
  94. inline void forEachPropertyInProtocol(Protocol *protocol, void (^callback)(objc_property_t))
  95. {
  96. unsigned count;
  97. auto properties = adoptSystem<objc_property_t[]>(protocol_copyPropertyList(protocol, &count));
  98. for (unsigned i = 0; i < count; ++i)
  99. callback(properties[i]);
  100. }
  101. template<char open, char close>
  102. void skipPair(const char*& position)
  103. {
  104. size_t count = 1;
  105. do {
  106. char c = *position++;
  107. if (!c)
  108. @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Malformed type encoding" userInfo:nil];
  109. if (c == open)
  110. ++count;
  111. else if (c == close)
  112. --count;
  113. } while (count);
  114. }
  115. class StringRange {
  116. WTF_MAKE_NONCOPYABLE(StringRange);
  117. public:
  118. StringRange(const char* begin, const char* end)
  119. : m_string(begin, end - begin)
  120. { }
  121. operator const char*() const { return m_string.data(); }
  122. const char* get() const { return m_string.data(); }
  123. private:
  124. CString m_string;
  125. };
  126. class StructBuffer {
  127. WTF_MAKE_NONCOPYABLE(StructBuffer);
  128. public:
  129. StructBuffer(const char* encodedType)
  130. {
  131. NSUInteger size, alignment;
  132. NSGetSizeAndAlignment(encodedType, &size, &alignment);
  133. m_buffer = fastAlignedMalloc(alignment, size);
  134. }
  135. ~StructBuffer() { fastAlignedFree(m_buffer); }
  136. operator void*() const { return m_buffer; }
  137. private:
  138. void* m_buffer;
  139. };
  140. template<typename DelegateType>
  141. typename DelegateType::ResultType parseObjCType(const char*& position)
  142. {
  143. ASSERT(*position);
  144. switch (*position++) {
  145. case 'c':
  146. return DelegateType::template typeInteger<char>();
  147. case 'i':
  148. return DelegateType::template typeInteger<int>();
  149. case 's':
  150. return DelegateType::template typeInteger<short>();
  151. case 'l':
  152. return DelegateType::template typeInteger<long>();
  153. case 'q':
  154. return DelegateType::template typeDouble<long long>();
  155. case 'C':
  156. return DelegateType::template typeInteger<unsigned char>();
  157. case 'I':
  158. return DelegateType::template typeInteger<unsigned>();
  159. case 'S':
  160. return DelegateType::template typeInteger<unsigned short>();
  161. case 'L':
  162. return DelegateType::template typeInteger<unsigned long>();
  163. case 'Q':
  164. return DelegateType::template typeDouble<unsigned long long>();
  165. case 'f':
  166. return DelegateType::template typeDouble<float>();
  167. case 'd':
  168. return DelegateType::template typeDouble<double>();
  169. case 'B':
  170. return DelegateType::typeBool();
  171. case 'v':
  172. return DelegateType::typeVoid();
  173. case '@': { // An object (whether statically typed or typed id)
  174. if (position[0] == '?' && position[1] == '<') {
  175. position += 2;
  176. const char* begin = position;
  177. skipPair<'<','>'>(position);
  178. return DelegateType::typeBlock(begin, position - 1);
  179. }
  180. if (*position == '"') {
  181. const char* begin = position + 1;
  182. const char* protocolPosition = strchr(begin, '<');
  183. const char* endOfType = strchr(begin, '"');
  184. position = endOfType + 1;
  185. // There's no protocol involved in this type, so just handle the class name.
  186. if (!protocolPosition || protocolPosition > endOfType)
  187. return DelegateType::typeOfClass(begin, endOfType);
  188. // We skipped the class name and went straight to the protocol, so this is an id type.
  189. if (begin == protocolPosition)
  190. return DelegateType::typeId();
  191. // We have a class name with a protocol. For now, ignore the protocol.
  192. return DelegateType::typeOfClass(begin, protocolPosition);
  193. }
  194. return DelegateType::typeId();
  195. }
  196. case '{': { // {name=type...} A structure
  197. const char* begin = position - 1;
  198. skipPair<'{','}'>(position);
  199. return DelegateType::typeStruct(begin, position);
  200. }
  201. // NOT supporting C strings, arrays, pointers, unions, bitfields, function pointers.
  202. case '*': // A character string (char *)
  203. case '[': // [array type] An array
  204. case '(': // (name=type...) A union
  205. case 'b': // bnum A bit field of num bits
  206. case '^': // ^type A pointer to type
  207. case '?': // An unknown type (among other things, this code is used for function pointers)
  208. // NOT supporting Objective-C Class, SEL
  209. case '#': // A class object (Class)
  210. case ':': // A method selector (SEL)
  211. default:
  212. return nil;
  213. }
  214. }
  215. extern "C" {
  216. // Forward declare some Objective-C runtime internal methods that are not API.
  217. const char *_protocol_getMethodTypeEncoding(Protocol *, SEL, BOOL isRequiredMethod, BOOL isInstanceMethod);
  218. id objc_initWeak(id *, id);
  219. void objc_destroyWeak(id *);
  220. bool _Block_has_signature(void *);
  221. const char * _Block_signature(void *);
  222. }