[interp] Small fixes (#11667)
[mono-project.git] / mono / mini / tramp-ppc.c
blob750af1434cd49875c3de807b5e7ca4d24aea1715
1 /**
2 * \file
3 * JIT trampoline code for PowerPC
5 * Authors:
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
8 * Carlos Valiente <yo@virutass.net>
9 * Andreas Faerber <andreas.faerber@web.de>
11 * (C) 2001 Ximian, Inc.
12 * (C) 2007-2008 Andreas Faerber
15 #include <config.h>
16 #include <glib.h>
18 #include <mono/metadata/abi-details.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/marshal.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/arch/ppc/ppc-codegen.h>
24 #include "mini.h"
25 #include "mini-ppc.h"
26 #include "mini-runtime.h"
28 #if 0
29 /* Same as mono_create_ftnptr, but doesn't require a domain */
30 static gpointer
31 mono_ppc_create_ftnptr (guint8 *code)
33 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
34 MonoPPCFunctionDescriptor *ftnptr = mono_global_codeman_reserve (sizeof (MonoPPCFunctionDescriptor));
36 ftnptr->code = code;
37 ftnptr->toc = NULL;
38 ftnptr->env = NULL;
40 MONO_PROFILER_RAISE (jit_code_buffer, (ftnptr, sizeof (MonoPPCFunctionDescriptor), MONO_PROFILER_CODE_BUFFER_HELPER, NULL));
42 return ftnptr;
43 #else
44 return code;
45 #endif
47 #endif
50 * Return the instruction to jump from code to target, 0 if not
51 * reachable with a single instruction
53 static guint32
54 branch_for_target_reachable (guint8 *branch, guint8 *target)
56 gint diff = target - branch;
57 g_assert ((diff & 3) == 0);
58 if (diff >= 0) {
59 if (diff <= 33554431)
60 return (18 << 26) | (diff);
61 } else {
62 /* diff between 0 and -33554432 */
63 if (diff >= -33554432)
64 return (18 << 26) | (diff & ~0xfc000000);
66 return 0;
70 * get_unbox_trampoline:
71 * @m: method pointer
72 * @addr: pointer to native code for @m
74 * when value type methods are called through the vtable we need to unbox the
75 * this argument. This method returns a pointer to a trampoline which does
76 * unboxing before calling the method
78 gpointer
79 mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
81 guint8 *code, *start;
82 int this_pos = 3;
83 guint32 short_branch;
84 MonoDomain *domain = mono_domain_get ();
85 int size = MONO_PPC_32_64_CASE (20, 32) + PPC_FTNPTR_SIZE;
87 addr = mono_get_addr_from_ftnptr (addr);
89 mono_domain_lock (domain);
90 start = code = mono_domain_code_reserve (domain, size);
91 code = mono_ppc_create_pre_code_ftnptr (code);
92 short_branch = branch_for_target_reachable (code + 4, addr);
93 if (short_branch)
94 mono_domain_code_commit (domain, code, size, 8);
95 mono_domain_unlock (domain);
97 if (short_branch) {
98 ppc_addi (code, this_pos, this_pos, MONO_ABI_SIZEOF (MonoObject));
99 ppc_emit32 (code, short_branch);
100 } else {
101 ppc_load_ptr (code, ppc_r0, addr);
102 ppc_mtctr (code, ppc_r0);
103 ppc_addi (code, this_pos, this_pos, MONO_ABI_SIZEOF (MonoObject));
104 ppc_bcctr (code, 20, 0);
106 mono_arch_flush_icache (start, code - start);
107 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m));
108 g_assert ((code - start) <= size);
109 /*g_print ("unbox trampoline at %d for %s:%s\n", this_pos, m->klass->name, m->name);
110 g_print ("unbox code is at %p for method at %p\n", start, addr);*/
112 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
114 return start;
118 * mono_arch_get_static_rgctx_trampoline:
120 * Create a trampoline which sets RGCTX_REG to ARG, then jumps to ADDR.
122 gpointer
123 mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr)
125 guint8 *code, *start, *p;
126 guint8 imm_buf [128];
127 guint32 short_branch;
128 MonoDomain *domain = mono_domain_get ();
129 int imm_size;
130 int size = MONO_PPC_32_64_CASE (24, (PPC_LOAD_SEQUENCE_LENGTH * 2) + 8) + PPC_FTNPTR_SIZE;
132 addr = mono_get_addr_from_ftnptr (addr);
134 /* Compute size of code needed to emit the arg */
135 p = imm_buf;
136 ppc_load_ptr (p, MONO_ARCH_RGCTX_REG, arg);
137 imm_size = p - imm_buf;
139 mono_domain_lock (domain);
140 start = code = mono_domain_code_reserve (domain, size);
141 code = mono_ppc_create_pre_code_ftnptr (code);
142 short_branch = branch_for_target_reachable (code + imm_size, addr);
143 if (short_branch)
144 mono_domain_code_commit (domain, code, size, imm_size + 4);
145 mono_domain_unlock (domain);
147 if (short_branch) {
148 ppc_load_ptr (code, MONO_ARCH_RGCTX_REG, arg);
149 ppc_emit32 (code, short_branch);
150 } else {
151 ppc_load_ptr (code, ppc_r0, addr);
152 ppc_mtctr (code, ppc_r0);
153 ppc_load_ptr (code, MONO_ARCH_RGCTX_REG, arg);
154 ppc_bcctr (code, 20, 0);
156 mono_arch_flush_icache (start, code - start);
157 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL));
158 g_assert ((code - start) <= size);
160 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
162 return start;
165 void
166 mono_arch_patch_callsite (guint8 *method_start, guint8 *code_ptr, guint8 *addr)
168 guint32 *code = (guint32*)code_ptr;
170 addr = mono_get_addr_from_ftnptr (addr);
172 /* This is the 'blrl' instruction */
173 --code;
176 * Note that methods are called also with the bl opcode.
178 if (((*code) >> 26) == 18) {
179 /*g_print ("direct patching\n");*/
180 ppc_patch ((guint8*)code, addr);
181 mono_arch_flush_icache ((guint8*)code, 4);
182 return;
185 /* Sanity check */
186 g_assert (mono_ppc_is_direct_call_sequence (code));
188 ppc_patch ((guint8*)code, addr);
191 void
192 mono_arch_patch_plt_entry (guint8 *code, gpointer *got, host_mgreg_t *regs, guint8 *addr)
194 guint32 ins1, ins2, offset;
196 /* Patch the jump table entry used by the plt entry */
198 /* Should be a lis+ori */
199 ins1 = ((guint32*)code)[0];
200 g_assert (ins1 >> 26 == 15);
201 ins2 = ((guint32*)code)[1];
202 g_assert (ins2 >> 26 == 24);
203 offset = ((ins1 & 0xffff) << 16) | (ins2 & 0xffff);
205 /* Either got or regs is set */
206 if (!got)
207 got = (gpointer*)(gsize) regs [30];
208 *(guint8**)((guint8*)got + offset) = addr;
211 /* Stack size for trampoline function
212 * PPC_MINIMAL_STACK_SIZE + 16 (args + alignment to ppc_magic_trampoline)
213 * + MonoLMF + 14 fp regs + 13 gregs + alignment
215 #define STACK (((PPC_MINIMAL_STACK_SIZE + 4 * sizeof (mgreg_t) + sizeof (MonoLMF) + 14 * sizeof (double) + 31 * sizeof (mgreg_t)) + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~(MONO_ARCH_FRAME_ALIGNMENT - 1))
217 /* Method-specific trampoline code fragment size */
218 #define METHOD_TRAMPOLINE_SIZE 64
220 /* Jump-specific trampoline code fragment size */
221 #define JUMP_TRAMPOLINE_SIZE 64
223 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
224 #define PPC_TOC_REG ppc_r2
225 #else
226 #define PPC_TOC_REG -1
227 #endif
230 * Stack frame description when the generic trampoline is called.
231 * caller frame
232 * --------------------
233 * MonoLMF
234 * -------------------
235 * Saved FP registers 0-13
236 * -------------------
237 * Saved general registers 0-30
238 * -------------------
239 * param area for 3 args to ppc_magic_trampoline
240 * -------------------
241 * linkage area
242 * -------------------
244 guchar*
245 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot)
247 char *tramp_name;
248 guint8 *buf, *code = NULL, *exception_branch;
249 int i, offset, offset_r14 = 0;
250 gconstpointer tramp_handler;
251 int size = MONO_PPC_32_64_CASE (700, 900);
252 GSList *unwind_ops = NULL;
253 MonoJumpInfo *ji = NULL;
255 /* Now we'll create in 'buf' the PowerPC trampoline code. This
256 is the trampoline code common to all methods */
258 code = buf = mono_global_codeman_reserve (size);
260 ppc_str_update (code, ppc_r1, -STACK, ppc_r1);
262 /* start building the MonoLMF on the stack */
263 offset = STACK - sizeof (double) * MONO_SAVED_FREGS;
264 for (i = 14; i < 32; i++) {
265 ppc_stfd (code, i, offset, ppc_r1);
266 offset += sizeof (double);
269 * now the integer registers.
271 offset = STACK - sizeof (MonoLMF) + G_STRUCT_OFFSET (MonoLMF, iregs);
272 ppc_str_multiple (code, ppc_r13, offset, ppc_r1);
274 /* Now save the rest of the registers below the MonoLMF struct, first 14
275 * fp regs and then the 31 gregs.
277 offset = STACK - sizeof (MonoLMF) - (14 * sizeof (double));
278 for (i = 0; i < 14; i++) {
279 ppc_stfd (code, i, offset, ppc_r1);
280 offset += sizeof (double);
282 #define GREGS_OFFSET (STACK - sizeof (MonoLMF) - (14 * sizeof (double)) - (31 * sizeof (mgreg_t)))
283 offset = GREGS_OFFSET;
284 for (i = 0; i < 31; i++) {
285 ppc_str (code, i, offset, ppc_r1);
286 if (i == ppc_r14) {
287 offset_r14 = offset;
289 offset += sizeof (mgreg_t);
292 /* we got here through a jump to the ctr reg, we must save the lr
293 * in the parent frame (we do it here to reduce the size of the
294 * method-specific trampoline)
296 ppc_mflr (code, ppc_r0);
297 ppc_str (code, ppc_r0, STACK + PPC_RET_ADDR_OFFSET, ppc_r1);
299 /* ok, now we can continue with the MonoLMF setup, mostly untouched
300 * from emit_prolog in mini-ppc.c
302 if (aot) {
303 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_get_lmf_addr");
304 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
305 ppc_ldptr (code, ppc_r2, sizeof (gpointer), ppc_r12);
306 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
307 #endif
308 ppc_mtlr (code, ppc_r12);
309 ppc_blrl (code);
310 } else {
311 ppc_load_func (code, PPC_CALL_REG, mono_get_lmf_addr);
312 ppc_mtlr (code, PPC_CALL_REG);
313 ppc_blrl (code);
315 /* we build the MonoLMF structure on the stack - see mini-ppc.h
316 * The pointer to the struct is put in ppc_r12.
318 ppc_addi (code, ppc_r12, ppc_sp, STACK - sizeof (MonoLMF));
319 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
320 /* new_lmf->previous_lmf = *lmf_addr */
321 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
322 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
323 /* *(lmf_addr) = r12 */
324 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
325 /* save method info (it's stored on the stack, so get it first). */
326 if ((tramp_type == MONO_TRAMPOLINE_JIT) || (tramp_type == MONO_TRAMPOLINE_JUMP)) {
327 ppc_ldr (code, ppc_r0, GREGS_OFFSET, ppc_r1);
328 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
329 } else {
330 ppc_load (code, ppc_r0, 0);
331 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
333 /* store the frame pointer of the calling method */
334 ppc_addi (code, ppc_r0, ppc_sp, STACK);
335 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
336 /* save the IP (caller ip) */
337 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
338 ppc_li (code, ppc_r0, 0);
339 } else {
340 ppc_ldr (code, ppc_r0, STACK + PPC_RET_ADDR_OFFSET, ppc_r1);
342 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
345 * Now we're ready to call trampoline (mgreg_t *regs, guint8 *code, gpointer value, guint8 *tramp)
346 * Note that the last argument is unused.
348 /* Arg 1: a pointer to the registers */
349 ppc_addi (code, ppc_r3, ppc_r1, GREGS_OFFSET);
351 /* Arg 2: code (next address to the instruction that called us) */
352 if (tramp_type == MONO_TRAMPOLINE_JUMP)
353 ppc_li (code, ppc_r4, 0);
354 else
355 ppc_ldr (code, ppc_r4, STACK + PPC_RET_ADDR_OFFSET, ppc_r1);
357 /* Arg 3: trampoline argument */
358 ppc_ldr (code, ppc_r5, GREGS_OFFSET, ppc_r1);
360 if (aot) {
361 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, g_strdup_printf ("trampoline_func_%d", tramp_type));
362 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
363 ppc_ldptr (code, ppc_r2, sizeof (gpointer), ppc_r12);
364 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
365 #endif
366 ppc_mtlr (code, ppc_r12);
367 ppc_blrl (code);
368 } else {
369 tramp_handler = mono_get_trampoline_func (tramp_type);
370 ppc_load_func (code, PPC_CALL_REG, tramp_handler);
371 ppc_mtlr (code, PPC_CALL_REG);
372 ppc_blrl (code);
375 /* OK, code address is now on r3, move it to r14 for now. */
376 if (!MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) {
377 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
378 ppc_ldptr (code, ppc_r2, sizeof (gpointer), ppc_r3);
379 ppc_ldptr (code, ppc_r3, 0, ppc_r3);
380 #endif
381 ppc_mr (code, ppc_r14, ppc_r3);
382 } else {
383 // TODO: is here function descriptor unpacking necessary?
384 /* we clobber r3 during interruption checking, so move it somewhere else */
385 ppc_mr (code, ppc_r14, ppc_r3);
389 * Now we restore the MonoLMF (see emit_epilogue in mini-ppc.c)
390 * and the rest of the registers, so the method called will see
391 * the same state as before we executed.
392 * The pointer to MonoLMF is in ppc_r12.
394 ppc_addi (code, ppc_r12, ppc_r1, STACK - sizeof (MonoLMF));
395 /* r3 = previous_lmf */
396 ppc_ldptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
397 /* r12 = lmf_addr */
398 ppc_ldptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
399 /* *(lmf_addr) = previous_lmf */
400 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
402 /* thread interruption check */
403 if (aot) {
404 g_error ("Not implemented");
405 } else {
406 gconstpointer checkpoint = mono_thread_force_interruption_checkpoint_noraise;
407 ppc_load_func (code, PPC_CALL_REG, checkpoint);
408 ppc_mtlr (code, PPC_CALL_REG);
410 ppc_blrl (code);
412 ppc_compare_reg_imm (code, 0, ppc_r3, 0);
413 exception_branch = code;
414 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
416 /* exception case */
418 /* restore caller frame, as we want to throw from there */
419 ppc_ldr (code, ppc_r14, offset_r14, ppc_r1); /* unclobber r14 */
420 ppc_ldr (code, ppc_r1, 0, ppc_r1);
421 ppc_ldr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_r1);
422 ppc_mtlr (code, ppc_r12);
424 if (aot) {
425 g_error ("Not implemented");
426 } else {
427 ppc_load_func (code, PPC_CALL_REG, mono_get_rethrow_preserve_exception_addr ());
428 ppc_ldr (code, PPC_CALL_REG, 0, PPC_CALL_REG);
429 ppc_mtctr (code, PPC_CALL_REG);
431 ppc_bcctr (code, 20, 0);
432 ppc_break (code); /* never reached */
434 ppc_patch (exception_branch, code);
436 /* no exception case */
437 if (!MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) {
438 /* we don't do any calls anymore, so code address can be safely moved
439 * into counter register */
440 ppc_mtctr (code, ppc_r14);
441 } else {
442 ppc_mr (code, ppc_r3, ppc_r14);
445 ppc_addi (code, ppc_r12, ppc_r1, STACK - sizeof (MonoLMF));
446 /* restore iregs */
447 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
448 /* restore fregs */
449 for (i = 14; i < 32; i++)
450 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
452 /* restore the volatile registers, we skip r1, of course */
453 offset = STACK - sizeof (MonoLMF) - (14 * sizeof (double));
454 for (i = 0; i < 14; i++) {
455 ppc_lfd (code, i, offset, ppc_r1);
456 offset += sizeof (double);
458 offset = STACK - sizeof (MonoLMF) - (14 * sizeof (double)) - (31 * sizeof (mgreg_t));
459 ppc_ldr (code, ppc_r0, offset, ppc_r1);
460 offset += 2 * sizeof (mgreg_t);
461 for (i = 2; i < 13; i++) {
462 if (i != PPC_TOC_REG && (i != 3 || tramp_type != MONO_TRAMPOLINE_RGCTX_LAZY_FETCH))
463 ppc_ldr (code, i, offset, ppc_r1);
464 offset += sizeof (mgreg_t);
467 /* Non-standard function epilogue. Instead of doing a proper
468 * return, we just jump to the compiled code.
470 /* Restore stack pointer and LR and jump to the code */
471 ppc_ldr (code, ppc_r1, 0, ppc_r1);
472 ppc_ldr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_r1);
473 ppc_mtlr (code, ppc_r12);
474 if (MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type))
475 ppc_blr (code);
476 else
477 ppc_bcctr (code, 20, 0);
479 /* Flush instruction cache, since we've generated code */
480 mono_arch_flush_icache (buf, code - buf);
481 MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL));
483 /* Sanity check */
484 g_assert ((code - buf) <= size);
486 g_assert (info);
487 tramp_name = mono_get_generic_trampoline_name (tramp_type);
488 *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops);
489 g_free (tramp_name);
491 return buf;
494 #define TRAMPOLINE_SIZE (MONO_PPC_32_64_CASE (24, (5+5+1+1)*4))
495 gpointer
496 mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
498 guint8 *code, *buf, *tramp;
499 guint32 short_branch;
501 tramp = mono_get_trampoline_code (tramp_type);
503 mono_domain_lock (domain);
504 code = buf = mono_domain_code_reserve_align (domain, TRAMPOLINE_SIZE, 4);
505 short_branch = branch_for_target_reachable (code + MONO_PPC_32_64_CASE (8, 5*4), tramp);
506 #ifdef __mono_ppc64__
507 /* FIXME: make shorter if possible */
508 #else
509 if (short_branch)
510 mono_domain_code_commit (domain, code, TRAMPOLINE_SIZE, 12);
511 #endif
512 mono_domain_unlock (domain);
514 if (short_branch) {
515 ppc_load_sequence (code, ppc_r0, (mgreg_t)(gsize) arg1);
516 ppc_emit32 (code, short_branch);
517 } else {
518 /* Prepare the jump to the generic trampoline code.*/
519 ppc_load_ptr (code, ppc_r0, tramp);
520 ppc_mtctr (code, ppc_r0);
522 /* And finally put 'arg1' in r0 and fly! */
523 ppc_load_ptr (code, ppc_r0, arg1);
524 ppc_bcctr (code, 20, 0);
527 /* Flush instruction cache, since we've generated code */
528 mono_arch_flush_icache (buf, code - buf);
529 MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type)));
531 g_assert ((code - buf) <= TRAMPOLINE_SIZE);
533 if (code_len)
534 *code_len = code - buf;
536 return buf;
539 static guint8*
540 emit_trampoline_jump (guint8 *code, guint8 *tramp)
542 guint32 short_branch = branch_for_target_reachable (code, tramp);
544 /* FIXME: we can save a few bytes here by committing if the
545 short branch is possible */
546 if (short_branch) {
547 ppc_emit32 (code, short_branch);
548 } else {
549 ppc_load_ptr (code, ppc_r0, tramp);
550 ppc_mtctr (code, ppc_r0);
551 ppc_bcctr (code, 20, 0);
554 return code;
557 gpointer
558 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot)
560 guint8 *tramp;
561 guint8 *code, *buf;
562 guint8 **rgctx_null_jumps;
563 int tramp_size;
564 int depth, index;
565 int i;
566 gboolean mrgctx;
567 MonoJumpInfo *ji = NULL;
568 GSList *unwind_ops = NULL;
570 mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
571 index = MONO_RGCTX_SLOT_INDEX (slot);
572 if (mrgctx)
573 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
574 for (depth = 0; ; ++depth) {
575 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
577 if (index < size - 1)
578 break;
579 index -= size - 1;
582 tramp_size = MONO_PPC_32_64_CASE (40, 52) + 12 * depth;
583 if (mrgctx)
584 tramp_size += 4;
585 else
586 tramp_size += 12;
587 if (aot)
588 tramp_size += 32;
590 code = buf = mono_global_codeman_reserve (tramp_size);
592 rgctx_null_jumps = g_malloc (sizeof (guint8*) * (depth + 2));
594 if (mrgctx) {
595 /* get mrgctx ptr */
596 ppc_mr (code, ppc_r4, PPC_FIRST_ARG_REG);
597 } else {
598 /* load rgctx ptr from vtable */
599 ppc_ldptr (code, ppc_r4, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context), PPC_FIRST_ARG_REG);
600 /* is the rgctx ptr null? */
601 ppc_compare_reg_imm (code, 0, ppc_r4, 0);
602 /* if yes, jump to actual trampoline */
603 rgctx_null_jumps [0] = code;
604 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
607 for (i = 0; i < depth; ++i) {
608 /* load ptr to next array */
609 if (mrgctx && i == 0)
610 ppc_ldptr (code, ppc_r4, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT, ppc_r4);
611 else
612 ppc_ldptr (code, ppc_r4, 0, ppc_r4);
613 /* is the ptr null? */
614 ppc_compare_reg_imm (code, 0, ppc_r4, 0);
615 /* if yes, jump to actual trampoline */
616 rgctx_null_jumps [i + 1] = code;
617 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
620 /* fetch slot */
621 ppc_ldptr (code, ppc_r4, sizeof (gpointer) * (index + 1), ppc_r4);
622 /* is the slot null? */
623 ppc_compare_reg_imm (code, 0, ppc_r4, 0);
624 /* if yes, jump to actual trampoline */
625 rgctx_null_jumps [depth + 1] = code;
626 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
627 /* otherwise return r4 */
628 /* FIXME: if we use r3 as the work register we can avoid this copy */
629 ppc_mr (code, ppc_r3, ppc_r4);
630 ppc_blr (code);
632 for (i = mrgctx ? 1 : 0; i <= depth + 1; ++i)
633 ppc_patch (rgctx_null_jumps [i], code);
635 g_free (rgctx_null_jumps);
637 /* move the rgctx pointer to the VTABLE register */
638 ppc_mr (code, MONO_ARCH_VTABLE_REG, ppc_r3);
640 if (aot) {
641 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, g_strdup_printf ("specific_trampoline_lazy_fetch_%u", slot));
642 /* Branch to the trampoline */
643 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
644 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
645 #endif
646 ppc_mtctr (code, ppc_r12);
647 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
648 } else {
649 tramp = (guint8*)mono_arch_create_specific_trampoline (GUINT_TO_POINTER (slot),
650 MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
652 /* jump to the actual trampoline */
653 code = emit_trampoline_jump (code, tramp);
656 mono_arch_flush_icache (buf, code - buf);
657 MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL));
659 g_assert (code - buf <= tramp_size);
661 char *name = mono_get_rgctx_fetch_trampoline_name (slot);
662 *info = mono_tramp_info_create (name, buf, code - buf, ji, unwind_ops);
663 g_free (name);
665 return buf;
668 guint8*
669 mono_arch_get_call_target (guint8 *code)
671 /* Should be a bl */
672 guint32 ins = ((guint32*)(gpointer)code) [-1];
674 if ((ins >> 26 == 18) && ((ins & 1) == 1) && ((ins & 2) == 0)) {
675 gint32 disp = (((gint32)ins) >> 2) & 0xffffff;
676 guint8 *target = code - 4 + (disp * 4);
678 return target;
679 } else {
680 return NULL;
684 guint32
685 mono_arch_get_plt_info_offset (guint8 *plt_entry, host_mgreg_t *regs, guint8 *code)
687 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
688 return ((guint32*)plt_entry) [8];
689 #else
690 return ((guint32*)plt_entry) [6];
691 #endif