PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/mono/mini/tramp-hppa.c

https://github.com/hollow87/mono
C | 434 lines | 247 code | 60 blank | 127 comment | 31 complexity | fbe055fdb80f6b439f659f29f87e0828 MD5 | raw file
  1. /*
  2. * tramp-hppa.c: JIT trampoline code for hppa
  3. *
  4. * Copyright (c) 2007 Randolph Chung
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. *
  24. */
  25. #include <config.h>
  26. #include <glib.h>
  27. #include <mono/arch/hppa/hppa-codegen.h>
  28. #include <mono/metadata/appdomain.h>
  29. #include <mono/metadata/marshal.h>
  30. #include <mono/metadata/tabledefs.h>
  31. #include "mini.h"
  32. #include "mini-hppa.h"
  33. /* sizeof (MonoLMF) == 320 + HPPA_STACK_LMF_OFFSET + linkage area (64 bytes)
  34. * leave some room to spare
  35. */
  36. #define TRAMP_STACK_SIZE 512
  37. /* Method-specific trampoline code fragment size */
  38. #define METHOD_TRAMPOLINE_SIZE 128
  39. /* Jump-specific trampoline code fragment size */
  40. #define JUMP_TRAMPOLINE_SIZE 64
  41. /*
  42. * mono_arch_get_unbox_trampoline:
  43. * @gsctx: the generic sharing context
  44. * @m: method pointer
  45. * @addr: pointer to native code for @m
  46. *
  47. * when value type methods are called through the vtable we need to unbox the
  48. * this argument. This method returns a pointer to a trampoline which does
  49. * unboxing before calling the method
  50. */
  51. gpointer
  52. mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer addr)
  53. {
  54. guint8 *code, *start;
  55. int this_pos = hppa_r26;
  56. MonoDomain *domain = mono_domain_get ();
  57. if (MONO_TYPE_ISSTRUCT (mono_method_signature (m)->ret))
  58. this_pos = hppa_r25;
  59. start = code = mono_domain_code_reserve (domain, 20);
  60. hppa_set (code, addr, hppa_r1);
  61. hppa_ldo (code, sizeof (MonoObject), this_pos, this_pos);
  62. hppa_bv (code, hppa_r0, hppa_r1);
  63. hppa_nop (code);
  64. mono_arch_flush_icache (start, code - start);
  65. g_assert ((code - start) <= 20);
  66. return start;
  67. }
  68. void
  69. mono_arch_patch_callsite (guint8 *method_start, guint8 *p, guint8 *addr)
  70. {
  71. guint32 *code = (void *)p;
  72. /* Search for and patch the calling sequence
  73. *
  74. * Possibilities are:
  75. *
  76. * CEE_CALL outputs the following sequence:
  77. *
  78. * ldil L'<addr>, r1
  79. * ldo R'<addr>, r1
  80. * bb,>=,n r1, 30, .+16
  81. * depwi 0, 31, 2, r1
  82. * ldw 4(r1), r19
  83. * ldw 0(r1), r1
  84. * ble 0(sr4,r1)
  85. * copy r31, rp
  86. * XXXXXXXXXXXXXXXX <- code points here
  87. */
  88. /* Go back to the branching insn */
  89. code -= 2;
  90. /* We can patch the code only if it is a direct call. In some cases
  91. * we can reach here via a reg-indirect call. In that case we can't
  92. * patch the callsite
  93. */
  94. if ((code[0] >> 26) == 0x39 && /* ble */
  95. (code[-4] >> 26) == 0x31 && /* bb */
  96. (code[-6] >> 26) == 0x08) /* ldil */ {
  97. hppa_patch (&code[-6], addr);
  98. mono_arch_flush_icache (&code[-6], 8);
  99. } else {
  100. printf("Can't patch callsite!\n");
  101. }
  102. }
  103. void
  104. mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
  105. {
  106. g_assert_not_reached ();
  107. }
  108. void
  109. mono_arch_nullify_class_init_trampoline (guint8 *code8, mgreg_t *regs)
  110. {
  111. guint32 *buf = (guint32 *)((unsigned long)code8 & ~3);
  112. guint32 *code = buf;
  113. code -= 2;
  114. if (code[0] == 0x08000240) /* nop - already nullified */
  115. return;
  116. g_assert ((code[0] >> 26) == 0x39); /* ble */
  117. hppa_nop (code);
  118. hppa_nop (code);
  119. mono_arch_flush_icache (buf, 8);
  120. }
  121. void
  122. mono_arch_nullify_plt_entry (guint8 *code, mgreg_t *regs)
  123. {
  124. g_assert_not_reached ();
  125. }
  126. #define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
  127. /*
  128. * Stack frame description when the generic trampoline is called.
  129. * caller frame
  130. * --------------------
  131. * MonoLMF
  132. * -------------------
  133. * incoming argument registers
  134. * -------------------
  135. * linkage area
  136. * -------------------
  137. */
  138. guchar*
  139. mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
  140. {
  141. guint8 *buf, *code = NULL;
  142. int i, offset;
  143. code = buf = mono_global_codeman_reserve (1024);
  144. /* Trampoline is called with "method" in r20 */
  145. hppa_stw (buf, hppa_r2, -20, hppa_sp);
  146. hppa_copy (buf, hppa_sp, hppa_r1);
  147. hppa_ldo (buf, TRAMP_STACK_SIZE, hppa_sp, hppa_sp);
  148. /* Save the MonoLMF structure on the stack */
  149. offset = HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, regs);
  150. for (i = 0; i < 32; i++) {
  151. if (HPPA_IS_SAVED_GREG (i)) {
  152. hppa_stw (buf, i, offset, hppa_r1);
  153. offset += sizeof(ulong);
  154. }
  155. }
  156. hppa_copy (buf, hppa_r1, hppa_r3);
  157. hppa_set (buf, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, fregs), hppa_r1);
  158. for (i = 0; i < 32; i++) {
  159. if (HPPA_IS_SAVED_FREG (i)) {
  160. hppa_fstdx (buf, i, hppa_r1, hppa_r3);
  161. hppa_ldo (buf, sizeof(double), hppa_r1, hppa_r1);
  162. }
  163. }
  164. /* Save the method info stored in r20 */
  165. hppa_stw (buf, hppa_r20, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, method), hppa_r3);
  166. hppa_stw (buf, hppa_r3, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, ebp), hppa_sp);
  167. if (tramp_type == MONO_TRAMPOLINE_JUMP) {
  168. hppa_stw (buf, hppa_r0, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, eip), hppa_r3);
  169. } else {
  170. hppa_stw (buf, hppa_r2, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, eip), hppa_r3);
  171. }
  172. /* Save the incoming arguments too, before they can trashed by the
  173. * call to the magic trampoline
  174. */
  175. offset = HPPA_STACK_LMF_OFFSET + sizeof (MonoLMF);
  176. for (i = hppa_r23; i <= hppa_r26; i++) {
  177. hppa_stw (buf, i, offset, hppa_r3);
  178. offset += sizeof(ulong);
  179. }
  180. hppa_stw (buf, hppa_r28, offset, hppa_r3);
  181. offset += sizeof(ulong);
  182. offset = ALIGN_TO (offset, sizeof(double));
  183. hppa_ldo (buf, offset, hppa_r3, hppa_r1);
  184. for (i = hppa_fr4; i <= hppa_fr7; i++) {
  185. hppa_fstds (buf, i, 0, hppa_r1);
  186. hppa_ldo (buf, sizeof(double), hppa_r1, hppa_r1);
  187. }
  188. /* Call mono_get_lmf_addr */
  189. hppa_set (buf, mono_get_lmf_addr, hppa_r1);
  190. hppa_depi (buf, 0, 31, 2, hppa_r1);
  191. hppa_ldw (buf, 0, hppa_r1, hppa_r1);
  192. hppa_ble (buf, 0, hppa_r1);
  193. hppa_copy (buf, hppa_r31, hppa_r2);
  194. /* r28 now points at the (MonoLMF **) for the current thread. */
  195. /* new_lmf->lmf_addr = lmf_addr */
  196. hppa_stw (buf, hppa_r28, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, lmf_addr), hppa_r3);
  197. /* new_lmf->previous_lmf = *lmf_addr */
  198. hppa_ldw (buf, 0, hppa_r28, hppa_r1);
  199. hppa_stw (buf, hppa_r1, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, previous_lmf), hppa_r3);
  200. /* *lmf_addr = new_lmf */
  201. hppa_ldo (buf, HPPA_STACK_LMF_OFFSET, hppa_r3, hppa_r1);
  202. hppa_stw (buf, hppa_r1, 0, hppa_r28);
  203. /* Call mono_magic_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tramp) */
  204. hppa_ldo (buf, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, regs), hppa_r3, hppa_r26);
  205. hppa_ldw (buf, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, method), hppa_r3, hppa_r24);
  206. if (tramp_type == MONO_TRAMPOLINE_JUMP)
  207. hppa_copy (buf, hppa_r0, hppa_r25);
  208. else {
  209. hppa_ldw (buf, -20, hppa_r3, hppa_r25);
  210. /* clear the lower two (privilege) bits */
  211. hppa_depi (buf, 0, 31, 2, hppa_r25);
  212. }
  213. hppa_copy (buf, hppa_r0, hppa_r23);
  214. if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
  215. hppa_set (buf, mono_class_init_trampoline, hppa_r1);
  216. else
  217. hppa_set (buf, mono_magic_trampoline, hppa_r1);
  218. hppa_depi (buf, 0, 31, 2, hppa_r1);
  219. hppa_ldw (buf, 0, hppa_r1, hppa_r1);
  220. hppa_ble (buf, 0, hppa_r1);
  221. hppa_copy (buf, hppa_r31, hppa_r2);
  222. /* Code address is now in r28 */
  223. /* Unwind LMF */
  224. hppa_ldw (buf, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, previous_lmf), hppa_r3, hppa_r20);
  225. hppa_ldw (buf, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, lmf_addr), hppa_r3, hppa_r21);
  226. hppa_stw (buf, hppa_r20, 0, hppa_r21);
  227. hppa_copy (buf, hppa_r28, hppa_r20);
  228. /* Restore arguments */
  229. offset = HPPA_STACK_LMF_OFFSET + sizeof (MonoLMF);
  230. for (i = hppa_r23; i <= hppa_r26; i++) {
  231. hppa_ldw (buf, offset, hppa_r3, i);
  232. offset += sizeof(ulong);
  233. }
  234. hppa_ldw (buf, offset, hppa_r3, hppa_r28);
  235. offset += sizeof(ulong);
  236. offset = ALIGN_TO (offset, sizeof(double));
  237. hppa_ldo (buf, offset, hppa_r3, hppa_r1);
  238. for (i = hppa_fr4; i <= hppa_fr7; i++) {
  239. hppa_fldds (buf, 0, hppa_r1, i);
  240. hppa_ldo (buf, sizeof(double), hppa_r1, hppa_r1);
  241. }
  242. /* Restore registers */
  243. hppa_set (buf, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, fregs), hppa_r1);
  244. for (i = 0; i < 32; i++) {
  245. if (HPPA_IS_SAVED_FREG (i)) {
  246. hppa_flddx (buf, hppa_r1, hppa_r3, i);
  247. hppa_ldo (buf, sizeof(double), hppa_r1, hppa_r1);
  248. }
  249. }
  250. hppa_copy (buf, hppa_r3, hppa_r1);
  251. offset = HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, regs);
  252. for (i = 0; i < 32; i++) {
  253. if (HPPA_IS_SAVED_GREG (i)) {
  254. hppa_ldw (buf, offset, hppa_r1, i);
  255. offset += sizeof(ulong);
  256. }
  257. }
  258. /* Jump to the compiled code in hppa_r28 */
  259. hppa_ldw (buf, -20, hppa_r1, hppa_r2);
  260. hppa_bv (buf, hppa_r0, hppa_r20);
  261. hppa_ldo (buf, -TRAMP_STACK_SIZE, hppa_sp, hppa_sp);
  262. g_assert ((buf - code) <= 1024);
  263. return code;
  264. }
  265. /**
  266. * mono_arch_create_class_init_trampoline:
  267. * @vtable: the type to initialize
  268. *
  269. * Creates a trampoline function to run a type initializer.
  270. * If the trampoline is called, it calls mono_runtime_class_init with the
  271. * given vtable, then patches the caller code so it does not get called any
  272. * more.
  273. *
  274. * Returns: a pointer to the newly created code
  275. */
  276. gpointer
  277. mono_arch_create_class_init_trampoline (MonoVTable *vtable)
  278. {
  279. guint8 *code, *buf, *tramp;
  280. tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
  281. /* This is the method-specific part of the trampoline. Its purpose is
  282. to provide the generic part with the MonoMethod *method pointer. */
  283. code = buf = mono_domain_code_reserve (vtable->domain, METHOD_TRAMPOLINE_SIZE);
  284. hppa_stw (buf, hppa_r2, -20, hppa_sp);
  285. hppa_copy (buf, hppa_r3, hppa_r1);
  286. hppa_copy (buf, hppa_sp, hppa_r3);
  287. hppa_stwm (buf, hppa_r1, 64, hppa_sp);
  288. /* mono_class_init_trampoline (regs, code, vtable, tramp) */
  289. hppa_copy (buf, hppa_r0, hppa_r26);
  290. hppa_copy (buf, hppa_r2, hppa_r25);
  291. hppa_set (buf, vtable, hppa_r24);
  292. hppa_copy (buf, hppa_r0, hppa_r23);
  293. hppa_set (buf, mono_class_init_trampoline, hppa_r1);
  294. hppa_depi (buf, 0, 31, 2, hppa_r1);
  295. hppa_ldw (buf, 0, hppa_r1, hppa_r1);
  296. hppa_ble (buf, 0, hppa_r1);
  297. hppa_copy (buf, hppa_r31, hppa_r2);
  298. hppa_ldw (buf, -20, hppa_r3, hppa_r2);
  299. hppa_ldo (buf, 64, hppa_r3, hppa_sp);
  300. hppa_bv (buf, hppa_r0, hppa_r2);
  301. hppa_ldwm (buf, -64, hppa_sp, hppa_r3);
  302. /* Flush instruction cache, since we've generated code */
  303. mono_arch_flush_icache (code, buf - code);
  304. /* Sanity check */
  305. g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
  306. return code;
  307. }
  308. static MonoJitInfo*
  309. create_specific_tramp (MonoMethod *method, guint8* tramp, MonoDomain *domain)
  310. {
  311. guint8 *code, *buf;
  312. MonoJitInfo *ji;
  313. code = buf = mono_domain_code_reserve (domain, 20);
  314. /* Call trampoline, with the "method" pointer in r20 */
  315. hppa_set (buf, tramp, hppa_r1);
  316. hppa_ldil (buf, hppa_lsel (method), hppa_r20);
  317. hppa_bv (buf, hppa_r0, hppa_r1);
  318. hppa_ldo (buf, hppa_rsel (method), hppa_r20, hppa_r20);
  319. /* Flush instruction cache, since we've generated code */
  320. mono_arch_flush_icache (code, buf - code);
  321. g_assert ((buf - code) <= 20);
  322. ji = g_new0 (MonoJitInfo, 1);
  323. ji->method = method;
  324. ji->code_start = code;
  325. ji->code_size = buf - code;
  326. return ji;
  327. }
  328. MonoJitInfo*
  329. mono_arch_create_jump_trampoline (MonoMethod *method)
  330. {
  331. guint8 *tramp;
  332. MonoDomain* domain = mono_domain_get ();
  333. tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP);
  334. return create_specific_tramp (method, tramp, domain);
  335. }
  336. /**
  337. * arch_create_jit_trampoline:
  338. * @method: pointer to the method info
  339. *
  340. * Creates a trampoline function for virtual methods. If the created
  341. * code is called it first starts JIT compilation of method,
  342. * and then calls the newly created method. It also replaces the
  343. * corresponding vtable entry (see mono_magic_trampoline).
  344. *
  345. * A trampoline consists of two parts: a main fragment, shared by all method
  346. * trampolines, and some code specific to each method, which hard-codes a
  347. * reference to that method and then calls the main fragment.
  348. *
  349. * The main fragment contains a call to 'arm_magic_trampoline', which performs
  350. * call to the JIT compiler and substitutes the method-specific fragment with
  351. * some code that directly calls the JIT-compiled method.
  352. *
  353. * Returns: a pointer to the newly created code
  354. */
  355. gpointer
  356. mono_arch_create_jit_trampoline (MonoMethod *method)
  357. {
  358. guint8 *tramp;
  359. MonoJitInfo *ji;
  360. MonoDomain* domain = mono_domain_get ();
  361. gpointer code_start;
  362. tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JIT);
  363. ji = create_specific_tramp (method, tramp, domain);
  364. code_start = ji->code_start;
  365. g_free (ji);
  366. return code_start;
  367. }
  368. gpointer
  369. mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 encoded_offset)
  370. {
  371. /* FIXME: implement! */
  372. g_assert_not_reached ();
  373. return NULL;
  374. }