New test.
[mono.git] / mono / mini / tramp-alpha.c
1 /*------------------------------------------------------------------*/
2 /*                                                                  */
3 /* Name        - tramp-alpha.c                                      */
4 /*                                                                  */
5 /* Function    - JIT trampoline code for Alpha.                     */
6 /*                                                                  */
7 /* Name        - Sergey Tikhonov (tsv@solvo.ru)                     */
8 /*                                                                  */
9 /* Date        - January, 2006                                      */
10 /*                                                                  */
11 /* Derivation  - From exceptions-amd64 & exceptions-ia64            */
12 /*               Dietmar Maurer (dietmar@ximian.com)                */
13 /*               Zoltan Varga (vargaz@gmail.com)                    */
14 /*                                                                  */
15 /*                                                                  */
16 /*------------------------------------------------------------------*/
17
18 /*------------------------------------------------------------------*/
19 /*                 D e f i n e s                                    */
20 /*------------------------------------------------------------------*/
21 #define NOT_IMPLEMENTED(x) \
22         g_error ("FIXME: %s is not yet implemented.", x);
23
24 #define ALPHA_DEBUG(x) \
25         if (mini_alpha_verbose_level) \
26                 g_debug ("ALPHA_DEBUG: %s is called.", x);
27
28 #define ALPHA_PRINT if (mini_alpha_verbose_level)
29
30 /*========================= End of Defines =========================*/
31
32 /*------------------------------------------------------------------*/
33 /*                 I n c l u d e s                                  */
34 /*------------------------------------------------------------------*/
35
36 #include <config.h>
37 #include <glib.h>
38 #include <string.h>
39
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/marshal.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/arch/alpha/alpha-codegen.h>
44 #include <mono/metadata/mono-debug-debugger.h>
45
46 #include "mini.h"
47 #include "mini-alpha.h"
48
49 /*========================= End of Includes ========================*/
50
51 /*------------------------------------------------------------------*/
52 /*                 T y p e d e f s                                  */
53 /*------------------------------------------------------------------*/
54
55 /*========================= End of Typedefs ========================*/
56
57 /*------------------------------------------------------------------*/
58 /*                   P r o t o t y p e s                            */
59 /*------------------------------------------------------------------*/
60
61 /*========================= End of Prototypes ======================*/
62
63 /*------------------------------------------------------------------*/
64 /*                 G l o b a l   V a r i a b l e s                  */
65 /*------------------------------------------------------------------*/
66
67
68 /*====================== End of Global Variables ===================*/
69
70 extern int mini_alpha_verbose_level;
71
72 /*------------------------------------------------------------------*/
73 /*                                                                  */
74 /* Name         - mono_arch_create_trampoline_code                  */
75 /*                                                                  */
76 /* Function     - Create the designated type of trampoline according*/
77 /*                to the 'tramp_type' parameter.                    */
78 /*                                                                  */
79 /*
80   This code should expect to be called by tramp stub function
81   On Alpha:
82   - pv points to start of stub function
83   - at points to start of this trampoline
84   - allocate stack to save all regs and lmfs
85   - save regs
86   - save lmf
87   - fill params for trampoline methods (They expect 4 params)
88   - call trampoline method (by standard call convention (pv + ra))
89   - save return value (r0)
90   - restore saved regs + lmfs
91   - restore stack (don't forget space allocated by stub)
92   - use saved return values as new address to give control to
93   - return or jump to new address (don't expect to return here -
94     don't save return address. RA will be holding return address
95     of original caller of tramp stub function). New address function
96     expect standart calling convention (pv)
97
98 */
99 /*------------------------------------------------------------------*/
100
101 guchar *
102 mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
103 {
104   unsigned int *buf, *code, *tramp;
105   int i, offset, framesize, off, lmf_offset, saved_regs_offset;
106   //int saved_fpregs_offset, saved_regs_offset, method_offset, tramp_offset;
107
108   gboolean has_caller;
109   
110   ALPHA_DEBUG("mono_arch_create_trampoline_code");
111   
112   if (tramp_type == MONO_TRAMPOLINE_JUMP)
113     has_caller = FALSE;
114   else
115     has_caller = TRUE;
116   
117   code = buf = mono_global_codeman_reserve (1024);
118   
119   framesize = 1024 + sizeof (MonoLMF);
120   framesize = (framesize +
121                (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
122   
123   offset = 16;
124   
125   // Expect that generated code is called with 2 parameters
126   // method and tramp (in a0 and a1)
127   
128   // Allocate stack
129   alpha_lda(code, alpha_sp, alpha_sp, -framesize);
130
131   /* store call convention parameters on stack.*/
132   alpha_stq( code, alpha_ra, alpha_sp, 0 ); // ra
133   alpha_stq( code, alpha_fp, alpha_sp, 8 ); // fp
134
135   saved_regs_offset = offset;
136
137   // Store all integer regs
138   for (i=0; i<30 /*alpha_pc*/; i++)
139     {
140       alpha_stq(code, i, alpha_sp, offset);
141       offset += 8;
142     }
143   
144   // Store all fp regs
145   for (i=0; i<alpha_fzero; i++)
146     {
147       alpha_stt(code, i, alpha_sp, offset);
148       offset += 8;
149     }
150
151   if (1)
152   {
153     // Save LMF (TSV_TODO don't forget callee saved regs)
154     lmf_offset = offset;
155     offset += sizeof (MonoLMF);
156
157     // Save PC
158     if (has_caller)
159       alpha_stq(code, alpha_ra, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip)));
160     else
161       alpha_stq(code, alpha_zero, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip)));
162     // Save FP
163     alpha_stq(code, alpha_fp, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp)));
164     
165     // Save method
166     alpha_ldq(code, alpha_r0, alpha_sp, framesize);
167     alpha_stq(code, alpha_r0, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, method)));
168
169     // Save SP
170     alpha_lda(code, alpha_r0, alpha_sp, (framesize+16));
171     alpha_stq(code, alpha_r0, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, rsp)));
172     
173     // Save GP
174     alpha_stq(code, alpha_gp, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, rgp)));
175     
176     // Get "lmf_addr"
177     off = (char *)code - (char *)buf;
178     off += 2*4;
179     
180     if (off % 8)
181       {
182         alpha_nop(code);
183         off += 4;
184       }
185     
186     // alpha_at points to start of this method !!!
187     alpha_ldq(code, alpha_r0, alpha_at, off);
188     alpha_br(code, alpha_zero, 2);
189     
190     *code = (unsigned int)(((unsigned long)mono_get_lmf_addr) & 0xFFFFFFFF);
191     code++;
192     *code = (unsigned int)((((unsigned long)mono_get_lmf_addr) >> 32) & 0xFFFFFFFF);
193     code++;
194     
195     /*
196      * The call might clobber argument registers, but they are already
197      * saved to the stack/global regs.
198      */
199     alpha_jsr(code, alpha_ra, alpha_r0, 0);
200     
201     // Save lmf_addr
202     alpha_stq(code, alpha_r0, alpha_sp,
203               (lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
204     // Load "previous_lmf" member of MonoLMF struct
205     alpha_ldq(code, alpha_r1, alpha_r0, 0);
206     
207     // Save it to MonoLMF struct
208     alpha_stq(code, alpha_r1, alpha_sp,
209               (lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
210     // Set new LMF
211     alpha_lda(code, alpha_r1, alpha_sp, lmf_offset);
212     alpha_stq(code, alpha_r1, alpha_r0, 0);
213   }
214
215
216   /* set the frame pointer */
217   alpha_mov1( code, alpha_sp, alpha_fp );
218   
219   /* Arg3 is the method/vtable ptr */
220   alpha_ldq(code, alpha_a2, alpha_sp, framesize);
221   //alpha_mov1(code, alpha_a0, alpha_a2);
222   
223   /* Arg4 is the trampoline address */
224   // Load PV from saved regs - later optimize it and load into a3 directly
225   alpha_ldq(code, alpha_pv, alpha_sp, (saved_regs_offset + (alpha_pv*8)));
226   alpha_mov1(code, alpha_pv, alpha_a3);
227   //alpha_mov1(code, alpha_a1, alpha_a3);
228   
229   /* Arg1 is the pointer to the saved registers */
230   alpha_lda(code, alpha_a0, alpha_sp, 16);
231
232   alpha_ldq(code, alpha_ra, alpha_sp, (saved_regs_offset + (alpha_ra*8)));  
233   /* Arg2 is the address of the calling code */
234   if (has_caller)
235     alpha_mov1(code, alpha_ra, alpha_a1);
236   else
237     alpha_mov1(code, alpha_zero, alpha_a1);
238   
239   /* Arg3 is the method/vtable ptr 
240      alpha_mov1(code, alpha_a0, alpha_a2);
241      
242      Arg4 is the trampoline address
243      alpha_mov1(code, alpha_a1, alpha_a3);
244   */
245   
246   if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
247     tramp = (unsigned int*)mono_class_init_trampoline;
248   else if (tramp_type == MONO_TRAMPOLINE_AOT)
249     tramp = (unsigned int*)mono_aot_trampoline;
250   else if (tramp_type == MONO_TRAMPOLINE_DELEGATE)
251     tramp = (unsigned int*)mono_delegate_trampoline;
252   else
253     tramp = (unsigned int*)mono_magic_trampoline;
254   
255   // Restore AT
256   alpha_ldq(code, alpha_at, alpha_sp, (saved_regs_offset + (alpha_at*8)));
257
258   off = (char *)code - (char *)buf;
259   off += 2*4;
260   
261   if (off % 8)
262     {
263       alpha_nop(code);
264       off += 4;
265     }
266   
267   // alpha_at points to start of this method !!!
268   alpha_ldq(code, alpha_pv, alpha_at, off);
269   alpha_br(code, alpha_zero, 2);
270   
271   *code = (unsigned int)(((unsigned long)tramp) & 0xFFFFFFFF);
272   code++;
273   *code = (unsigned int)((((unsigned long)tramp) >> 32) & 0xFFFFFFFF);
274   code++;
275   
276   alpha_jsr(code, alpha_ra, alpha_pv, 0);
277   
278   alpha_stq(code, alpha_r0, alpha_sp, framesize);
279   
280   /* Restore LMF */
281   if (1)
282   {
283     /* Restore previous lmf */
284     alpha_ldq(code, alpha_at, alpha_sp,
285               (lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf)));
286     alpha_ldq(code, alpha_ra, alpha_sp,
287               (lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr)));
288     alpha_stq(code, alpha_at, alpha_ra, 0);
289   }
290   
291   offset = 16;
292   
293   // Restore all integer regs
294   for (i=0; i<30 /*alpha_pc*/; i++)
295     {
296       alpha_ldq(code, i, alpha_sp, offset);
297       offset += 8;
298     }
299
300   // Restore all float regs
301   for (i=0; i<alpha_fzero; i++)
302     {
303       alpha_ldt(code, i, alpha_sp, offset);
304       offset += 8;
305     }
306   
307   alpha_ldq(code, alpha_r0, alpha_sp, framesize);
308   
309   // Restore stack
310   alpha_lda(code, alpha_sp, alpha_sp, (framesize+16));
311   
312   if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
313     alpha_ret (code, alpha_ra, 1);
314   else
315     {
316       /* call the compiled method */
317       // It will expect correct call frame 
318       
319       alpha_mov1(code, alpha_r0, alpha_pv);
320       alpha_jsr (code, alpha_zero, alpha_pv, 0);
321     }
322   
323   g_assert (((char *)code - (char *)buf) <= 1024);
324   
325   mono_arch_flush_icache ((guchar *)buf, (char *)code - (char *)buf);
326   
327   return (guchar *)buf;
328 }
329
330 /*========================= End of Function ========================*/
331
332 /*------------------------------------------------------------------*/
333 /*                                                                  */
334 /* Name         - mono_arch_create_jit_trampoline                   */
335 /*                                                                  */
336 /* Function     - Creates a trampoline function for virtual methods.*/
337 /*                If the created code is called it first starts JIT */
338 /*                compilation and then calls the newly created      */
339 /*                method. It also replaces the corresponding vtable */
340 /*                entry (see s390_magic_trampoline).                */
341 /*                                                                  */
342 /*                A trampoline consists of two parts: a main        */
343 /*                fragment, shared by all method trampolines, and   */
344 /*                and some code specific to each method, which      */
345 /*                hard-codes a reference to that method and then    */
346 /*                calls the main fragment.                          */
347 /*                                                                  */
348 /*                The main fragment contains a call to              */
349 /*                's390_magic_trampoline', which performs a call    */
350 /*                to the JIT compiler and substitutes the method-   */
351 /*                specific fragment with some code that directly    */
352 /*                calls the JIT-compiled method.                    */
353 /*                                                                  */
354 /* Parameter    - method - Pointer to the method information        */
355 /*                                                                  */
356 /* Returns      - A pointer to the newly created code               */
357 /*                                                                  */
358 /*------------------------------------------------------------------*/
359
360 gpointer
361 mono_arch_create_jit_trampoline (MonoMethod *method)
362 {
363         ALPHA_DEBUG("mono_arch_create_jit_trampoline: check MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE define");
364
365 //      NOT_IMPLEMENTED("mono_arch_create_jit_trampoline: check MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE define");
366
367         return 0;
368 }
369
370 /*========================= End of Function ========================*/
371
372 /*------------------------------------------------------------------*/
373 /*                                                                  */
374 /* Name         - mono_arch_create_jump_trampoline                  */
375 /*                                                                  */
376 /* Function     - Create the designated type of trampoline according*/
377 /*                to the 'tramp_type' parameter.                    */
378 /*                                                                  */
379 /*------------------------------------------------------------------*/
380
381 MonoJitInfo *
382 mono_arch_create_jump_trampoline (MonoMethod *method)
383 {
384         ALPHA_DEBUG("mono_arch_create_jump_trampoline");
385
386         NOT_IMPLEMENTED("mono_arch_create_jump_trampoline");
387         
388         return 0;
389 }
390
391 /*========================= End of Function ========================*/
392
393 /*------------------------------------------------------------------*/
394 /*                                                                  */
395 /* Name         - mono_arch_create_specific_trampoline              */
396 /*                                                                  */
397 /* Function     - ???Create the designated type of trampoline according*/
398 /*                to the 'tramp_type' parameter.                    */
399 /*                                                                  */
400 /* This method should create a stub code that will transfer
401    control to corresponding trampoline. We need to pass "arg1" and
402    start address of this stab method to trampoline code.
403    We should not modify any registers!!!
404    For Alpha:
405    - allocate 2 qword on stack
406    - save stab start address on 8(sp)
407    - save "arg1" on 0(sp)
408    - jump to trampoline code keeping original caller return address
409      in ra
410 */
411 /*------------------------------------------------------------------*/
412
413 #define TRAMPOLINE_SIZE 64
414
415 gpointer
416 mono_arch_create_specific_trampoline (gpointer arg1,
417         MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
418 {
419   unsigned int *code, *buf, *tramp, *real_code;
420   int offset, size; //, jump_offset;
421   
422   ALPHA_DEBUG("mono_arch_create_specific_trampoline");
423   
424   tramp = (unsigned int *)mono_get_trampoline_code (tramp_type);
425   
426   code = buf = g_alloca (TRAMPOLINE_SIZE);
427   
428   /* push trampoline address */
429   //amd64_lea_membase (code, AMD64_R11, AMD64_RIP, -7);
430   //amd64_push_reg (code, AMD64_R11);
431   
432   // Allocate two qwords on stack
433   alpha_lda(code, alpha_sp, alpha_sp, -16);
434
435   // Save my stub address at 8(sp)
436   alpha_stq(code, alpha_pv, alpha_sp, 8);
437   
438   // Load arg1 into alpha_at
439   offset = (char *)code - (char *)buf;
440   offset += 2*4;
441   if (offset % 8)
442     {
443       alpha_nop(code);
444       offset += 4;
445     }
446   
447   alpha_ldq(code, alpha_at, alpha_pv, offset);
448   alpha_br(code, alpha_zero, 2);
449   
450   *code = (unsigned int)(((unsigned long)arg1) & 0xFFFFFFFF);
451   code++;
452   *code = (unsigned int)((((unsigned long)arg1) >> 32) & 0xFFFFFFFF);
453   code++;
454   
455   // Store arg1 on stack
456   alpha_stq(code, alpha_at, alpha_sp, 0);
457   
458   offset = (char *)code - (char *)buf;
459   offset += 2*4;
460   if (offset % 8)
461     {
462       alpha_nop(code);
463       offset += 4;
464     }
465   
466   alpha_ldq(code, alpha_at, alpha_pv, offset);
467   alpha_br(code, alpha_zero, 2);
468   
469   *code = (unsigned int)(((unsigned long)tramp) & 0xFFFFFFFF);
470   code++;
471   *code = (unsigned int)((((unsigned long)tramp) >> 32) & 0xFFFFFFFF);
472   code++;
473   
474   // Jump to trampoline
475   alpha_jmp(code, alpha_zero, alpha_at, 0);
476   
477   g_assert (((char *)code - (char *)buf) <= TRAMPOLINE_SIZE);
478   mono_domain_lock (domain);
479   /*
480    * FIXME: Changing the size to code - buf causes strange crashes during
481    * mcs bootstrap.
482    */
483   real_code = mono_code_manager_reserve (domain->code_mp, TRAMPOLINE_SIZE);
484   size = (char *)code - (char *)buf;
485   mono_domain_unlock (domain);
486   
487   memcpy (real_code, buf, size);
488  
489   ALPHA_PRINT 
490         g_debug("mono_arch_create_specific_trampoline: Target: %p, Arg1: %p",
491          real_code, arg1);
492   
493   mono_jit_stats.method_trampolines++;
494   
495   if (code_len)
496     *code_len = size;
497   
498   mono_arch_flush_icache ((guchar *)real_code, size);
499   
500   return real_code;
501 }
502 /*========================= End of Function ========================*/
503
504 void
505 mono_arch_nullify_class_init_trampoline (guint8 *code, gssize *regs)
506 {
507   unsigned int *pcode = (unsigned int *)code;
508
509   ALPHA_DEBUG("mono_arch_nullify_class_init_trampoline");
510
511 }
512
513
514 void
515 mono_arch_patch_delegate_trampoline (guint8 *code, guint8 *tramp,
516                                      gssize *regs, guint8 *addr)
517 {
518   ALPHA_DEBUG("mono_arch_patch_delegate_trampoline");
519 }
520
521 void
522 mono_arch_patch_callsite (guint8 *code, guint8 *addr)
523 {
524   unsigned long *p = (unsigned int *)(code-12);
525   
526   unsigned int *pcode = (unsigned int *)code;
527   unsigned long gp = (unsigned long)pcode;
528   unsigned int call_addr_inst;
529   short high_offset, low_offset;
530
531   ALPHA_DEBUG("mono_arch_patch_callsite");
532
533   // Code points to the next instruction after the "jsr"
534   // In current implementation where we put jump addresses
535   // inside the code - we need to put "new" address into
536   // "code-12"
537
538   // With new method of using GOT we need to find address
539   // where function address is stored
540   // code points to two insts:
541   // ldah gp, high_offset(ra)
542   // lda gp, low_offset(gp)
543   // 
544
545   high_offset = *((short *)pcode);
546   low_offset = *((short *)(pcode + 1));
547
548   gp += 65536 * high_offset + low_offset;
549
550   call_addr_inst = *(pcode - 2);
551
552   // Check for load address instruction
553   // It should be ldq t12, offset(gp)
554   if ((call_addr_inst & 0xFFFF0000) == 0xA77D0000)
555   {
556     gp += *((short *)(pcode - 2));
557
558     p = (unsigned long *)gp;
559
560     ALPHA_PRINT g_debug("Patch callsite at %p to %p\n", p, addr);
561
562     // TODO - need to to interlocked update here
563     *p = (unsigned long)addr;
564   }
565 }
566
567 /*
568  * mono_arch_get_unbox_trampoline:
569  * @m: method pointer
570  * @addr: pointer to native code for @m
571  *
572  * when value type methods are called through the vtable we need to unbox the
573  * this argument. This method returns a pointer to a trampoline which does
574  * unboxing before calling the method
575  */
576 gpointer
577 mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
578 {
579   unsigned int *code, *start_code;
580   int this_reg = 16; //R16
581   int off;
582   MonoDomain *domain = mono_domain_get ();
583
584   ALPHA_DEBUG("mono_arch_get_unbox_trampoline");
585
586   if (!mono_method_signature (m)->ret->byref &&
587       MONO_TYPE_ISSTRUCT (mono_method_signature (m)->ret))
588     this_reg = 17; //R17
589
590   mono_domain_lock (domain);
591   start_code = code = (unsigned int *)mono_code_manager_reserve (domain->code_mp, 32);
592   mono_domain_unlock (domain);
593
594   // Adjust this by size of MonoObject
595   alpha_addq_(code, this_reg, sizeof(MonoObject), this_reg);  // 0
596   alpha_bsr(code, alpha_pv, 2);  // 4
597
598   *code = (unsigned int)(((unsigned long)addr) & 0xFFFFFFFF);
599   code++;
600   *code = (unsigned int)((((unsigned long)addr) >> 32) & 0xFFFFFFFF);
601   code++;
602
603   // Load "addr" into PV (R12)
604   alpha_ldq(code, alpha_pv, alpha_pv, 0);
605
606   // Jump to addr
607   alpha_jsr(code, alpha_zero, alpha_pv, 0);
608
609   g_assert (((char *)code - (char *)start_code) < 32);
610
611   mono_arch_flush_icache (start_code, (char *)code - (char *)start_code);
612
613   return start_code;
614 }
615
616 void
617 mono_arch_nullify_plt_entry (guint8 *code)
618 {
619         g_assert_not_reached ();
620 }
621
622 void
623 mono_arch_patch_plt_entry (guint8 *code, guint8 *addr)
624 {
625         g_assert_not_reached ();
626 }
627
628 /*
629  * This method is only called when running in the Mono Debugger.
630  */
631 guint8 *
632 mono_debugger_create_notification_function (MonoCodeManager *codeman)
633 {
634   guint8 *code;
635   unsigned int *buf;
636
637   code = mono_code_manager_reserve (codeman, 16);
638   buf = (unsigned int *)code;
639
640   *buf = 0;
641
642   alpha_call_pal(buf, 0x80);
643   alpha_ret(buf, alpha_ra, 1);
644   //x86_breakpoint (buf);
645   //x86_ret (buf);
646
647   return code;
648 }
649