objc-msg-win32.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. #include "objc-private.h"
  2. // out-of-band parameter to objc_msgForward
  3. #define kFwdMsgSend 1
  4. #define kFwdMsgSendStret 0
  5. // objc_msgSend parameters
  6. #define SELF 8[ebp]
  7. #define SUPER 8[ebp]
  8. #define SELECTOR 12[ebp]
  9. #define FIRST_ARG 16[ebp]
  10. // objc_msgSend_stret parameters
  11. #define STRUCT_ADDR 8[ebp]
  12. #define SELF_STRET 12[ebp]
  13. #define SUPER_STRET 12[ebp]
  14. #define SELECTOR_STRET 16[ebp]
  15. // objc_super parameter to sendSuper
  16. #define super_receiver 0
  17. #define super_class 4
  18. // struct objc_class fields
  19. #define isa 0
  20. #define cache 32
  21. // struct objc_method fields
  22. #define method_name 0
  23. #define method_imp 8
  24. // struct objc_cache fields
  25. #define mask 0
  26. #define occupied 4
  27. #define buckets 8
  28. void *_objc_forward_handler = NULL;
  29. void *_objc_forward_stret_handler = NULL;
  30. __declspec(naked) Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
  31. {
  32. __asm {
  33. push ebp
  34. mov ebp, esp
  35. mov ecx, SELECTOR
  36. mov edx, SELF
  37. // CacheLookup WORD_RETURN, CACHE_GET
  38. push edi
  39. mov edi, cache[edx]
  40. push esi
  41. mov esi, mask[edi]
  42. mov edx, ecx
  43. shr edx, 2
  44. SCAN:
  45. and edx, esi
  46. mov eax, buckets[edi][edx*4]
  47. test eax, eax
  48. je MISS
  49. cmp ecx, method_name[eax]
  50. je HIT
  51. add edx, 1
  52. jmp SCAN
  53. MISS:
  54. xor eax, eax
  55. pop esi
  56. pop edi
  57. leave
  58. ret
  59. HIT:
  60. mov ecx, FIRST_ARG
  61. cmp ecx, method_imp[eax]
  62. je MISS
  63. pop esi
  64. pop edi
  65. leave
  66. ret
  67. }
  68. }
  69. __declspec(naked) IMP _cache_getImp(Class cls, SEL sel)
  70. {
  71. __asm {
  72. push ebp
  73. mov ebp, esp
  74. mov ecx, SELECTOR
  75. mov edx, SELF
  76. // CacheLookup WORD_RETURN, CACHE_GET
  77. push edi
  78. mov edi, cache[edx]
  79. push esi
  80. mov esi, mask[edi]
  81. mov edx, ecx
  82. shr edx, 2
  83. SCAN:
  84. and edx, esi
  85. mov eax, buckets[edi][edx*4]
  86. test eax, eax
  87. je MISS
  88. cmp ecx, method_name[eax]
  89. je HIT
  90. add edx, 1
  91. jmp SCAN
  92. MISS:
  93. pop esi
  94. pop edi
  95. xor eax, eax
  96. leave
  97. ret
  98. HIT:
  99. pop esi
  100. pop edi
  101. mov eax, method_imp[eax]
  102. leave
  103. ret
  104. }
  105. }
  106. OBJC_EXPORT __declspec(naked) id objc_msgSend(id a, SEL b, ...)
  107. {
  108. __asm {
  109. push ebp
  110. mov ebp, esp
  111. // load receiver and selector
  112. mov ecx, SELECTOR
  113. mov eax, SELF
  114. // check whether receiver is nil
  115. test eax, eax
  116. je NIL
  117. // receiver (in eax) is non-nil: search the cache
  118. mov edx, isa[eax]
  119. // CacheLookup WORD_RETURN, MSG_SEND
  120. push edi
  121. mov edi, cache[edx]
  122. push esi
  123. mov esi, mask[edi]
  124. mov edx, ecx
  125. shr edx, 2
  126. SCAN:
  127. and edx, esi
  128. mov eax, buckets[edi][edx*4]
  129. test eax, eax
  130. je MISS
  131. cmp ecx, method_name[eax]
  132. je HIT
  133. add edx, 1
  134. jmp SCAN
  135. HIT:
  136. mov eax, method_imp[eax]
  137. pop esi
  138. pop edi
  139. mov edx, kFwdMsgSend
  140. leave
  141. jmp eax
  142. // cache miss: search method lists
  143. MISS:
  144. pop esi
  145. pop edi
  146. mov edx, SELF
  147. mov eax, isa[edx]
  148. // MethodTableLookup WORD_RETURN, MSG_SEND
  149. push eax
  150. push ecx
  151. push edx
  152. call _class_lookupMethodAndLoadCache3
  153. mov edx, kFwdMsgSend
  154. leave
  155. jmp eax
  156. // message send to nil: return zero
  157. NIL:
  158. // eax is already zero
  159. mov edx, 0
  160. leave
  161. ret
  162. }
  163. }
  164. OBJC_EXPORT __declspec(naked) double objc_msgSend_fpret(id a, SEL b, ...)
  165. {
  166. __asm {
  167. push ebp
  168. mov ebp, esp
  169. // load receiver and selector
  170. mov ecx, SELECTOR
  171. mov eax, SELF
  172. // check whether receiver is nil
  173. test eax, eax
  174. je NIL
  175. // receiver (in eax) is non-nil: search the cache
  176. mov edx, isa[eax]
  177. // CacheLookup WORD_RETURN, MSG_SEND
  178. push edi
  179. mov edi, cache[edx]
  180. push esi
  181. mov esi, mask[edi]
  182. mov edx, ecx
  183. shr edx, 2
  184. SCAN:
  185. and edx, esi
  186. mov eax, buckets[edi][edx*4]
  187. test eax, eax
  188. je MISS
  189. cmp ecx, method_name[eax]
  190. je HIT
  191. add edx, 1
  192. jmp SCAN
  193. HIT:
  194. mov eax, method_imp[eax]
  195. pop esi
  196. pop edi
  197. mov edx, kFwdMsgSend
  198. leave
  199. jmp eax
  200. // cache miss: search method lists
  201. MISS:
  202. pop esi
  203. pop edi
  204. mov edx, SELF
  205. mov eax, isa[edx]
  206. // MethodTableLookup WORD_RETURN, MSG_SEND
  207. push eax
  208. push ecx
  209. push edx
  210. call _class_lookupMethodAndLoadCache3
  211. mov edx, kFwdMsgSend
  212. leave
  213. jmp eax
  214. // message send to nil: return zero
  215. NIL:
  216. fldz
  217. leave
  218. ret
  219. }
  220. }
  221. OBJC_EXPORT __declspec(naked) id objc_msgSendSuper(struct objc_super *a, SEL b, ...)
  222. {
  223. __asm {
  224. push ebp
  225. mov ebp, esp
  226. // load class and selector
  227. mov eax, SUPER
  228. mov ecx, SELECTOR
  229. mov edx, super_class[eax]
  230. // search the cache (class in edx)
  231. // CacheLookup WORD_RETURN, MSG_SENDSUPER
  232. push edi
  233. mov edi, cache[edx]
  234. push esi
  235. mov esi, mask[edi]
  236. mov edx, ecx
  237. shr edx, 2
  238. SCAN:
  239. and edx, esi
  240. mov eax, buckets[edi][edx*4]
  241. test eax, eax
  242. je MISS
  243. cmp ecx, method_name[eax]
  244. je HIT
  245. add edx, 1
  246. jmp SCAN
  247. HIT:
  248. mov eax, method_imp[eax]
  249. pop esi
  250. pop edi
  251. mov edx, SUPER
  252. mov edx, super_receiver[edx]
  253. mov SUPER, edx
  254. mov edx, kFwdMsgSend
  255. leave
  256. jmp eax
  257. // cache miss: search method lists
  258. MISS:
  259. pop esi
  260. pop edi
  261. mov eax, SUPER
  262. mov edx, super_receiver[eax]
  263. mov SUPER, edx
  264. mov eax, super_class[eax]
  265. // MethodTableLookup WORD_RETURN, MSG_SENDSUPER
  266. push eax
  267. push ecx
  268. push edx
  269. call _class_lookupMethodAndLoadCache3
  270. mov edx, kFwdMsgSend
  271. leave
  272. jmp eax
  273. }
  274. }
  275. OBJC_EXPORT __declspec(naked) void objc_msgSend_stret(void)
  276. {
  277. __asm {
  278. push ebp
  279. mov ebp, esp
  280. // load receiver and selector
  281. mov ecx, SELECTOR_STRET
  282. mov eax, SELF_STRET
  283. // check whether receiver is nil
  284. test eax, eax
  285. je NIL
  286. // receiver (in eax) is non-nil: search the cache
  287. mov edx, isa[eax]
  288. // CacheLookup WORD_RETURN, MSG_SEND
  289. push edi
  290. mov edi, cache[edx]
  291. push esi
  292. mov esi, mask[edi]
  293. mov edx, ecx
  294. shr edx, 2
  295. SCAN:
  296. and edx, esi
  297. mov eax, buckets[edi][edx*4]
  298. test eax, eax
  299. je MISS
  300. cmp ecx, method_name[eax]
  301. je HIT
  302. add edx, 1
  303. jmp SCAN
  304. HIT:
  305. mov eax, method_imp[eax]
  306. pop esi
  307. pop edi
  308. mov edx, kFwdMsgSendStret
  309. leave
  310. jmp eax
  311. // cache miss: search method lists
  312. MISS:
  313. pop esi
  314. pop edi
  315. mov edx, SELF_STRET
  316. mov eax, isa[edx]
  317. // MethodTableLookup WORD_RETURN, MSG_SEND
  318. push eax
  319. push ecx
  320. push edx
  321. call _class_lookupMethodAndLoadCache3
  322. mov edx, kFwdMsgSendStret
  323. leave
  324. jmp eax
  325. // message send to nil: return zero
  326. NIL:
  327. // eax is already zero
  328. mov edx, 0
  329. leave
  330. ret
  331. }
  332. }
  333. OBJC_EXPORT __declspec(naked) id objc_msgSendSuper_stret(struct objc_super *a, SEL b, ...)
  334. {
  335. __asm {
  336. push ebp
  337. mov ebp, esp
  338. // load class and selector
  339. mov eax, SUPER_STRET
  340. mov ecx, SELECTOR_STRET
  341. mov edx, super_class[eax]
  342. // search the cache (class in edx)
  343. // CacheLookup WORD_RETURN, MSG_SENDSUPER
  344. push edi
  345. mov edi, cache[edx]
  346. push esi
  347. mov esi, mask[edi]
  348. mov edx, ecx
  349. shr edx, 2
  350. SCAN:
  351. and edx, esi
  352. mov eax, buckets[edi][edx*4]
  353. test eax, eax
  354. je MISS
  355. cmp ecx, method_name[eax]
  356. je HIT
  357. add edx, 1
  358. jmp SCAN
  359. HIT:
  360. mov eax, method_imp[eax]
  361. pop esi
  362. pop edi
  363. mov edx, SUPER_STRET
  364. mov edx, super_receiver[edx]
  365. mov SUPER_STRET, edx
  366. mov edx, kFwdMsgSendStret
  367. leave
  368. jmp eax
  369. // cache miss: search method lists
  370. MISS:
  371. pop esi
  372. pop edi
  373. mov eax, SUPER_STRET
  374. mov edx, super_receiver[eax]
  375. mov SUPER_STRET, edx
  376. mov eax, super_class[eax]
  377. // MethodTableLookup WORD_RETURN, MSG_SENDSUPER
  378. push eax
  379. push ecx
  380. push edx
  381. call _class_lookupMethodAndLoadCache3
  382. mov edx, kFwdMsgSendStret
  383. leave
  384. jmp eax
  385. }
  386. }
  387. OBJC_EXPORT __declspec(naked) id _objc_msgForward(id a, SEL b, ...)
  388. {
  389. __asm {
  390. mov ecx, _objc_forward_handler
  391. jmp ecx
  392. }
  393. }
  394. OBJC_EXPORT __declspec(naked) id _objc_msgForward_stret(id a, SEL b, ...)
  395. {
  396. __asm {
  397. mov ecx, _objc_forward_stret_handler
  398. jmp ecx
  399. }
  400. }
  401. __declspec(naked) id _objc_msgForward_cached(id a, SEL b, ...)
  402. {
  403. __asm {
  404. cmp edx, kFwdMsgSendStret
  405. je STRET
  406. jmp _objc_msgForward
  407. STRET:
  408. jmp _objc_msgForward_stret
  409. }
  410. }
  411. OBJC_EXPORT __declspec(naked) void method_invoke(void)
  412. {
  413. __asm {
  414. push ebp
  415. mov ebp, esp
  416. mov ecx, SELECTOR
  417. mov edx, method_name[ecx]
  418. mov eax, method_imp[ecx]
  419. mov SELECTOR, edx
  420. leave
  421. jmp eax
  422. }
  423. }
  424. OBJC_EXPORT __declspec(naked) void method_invoke_stret(void)
  425. {
  426. __asm {
  427. push ebp
  428. mov ebp, esp
  429. mov ecx, SELECTOR_STRET
  430. mov edx, method_name[ecx]
  431. mov eax, method_imp[ecx]
  432. mov SELECTOR_STRET, edx
  433. leave
  434. jmp eax
  435. }
  436. }