2006-08-01 Zoltan Varga <vargaz@gmail.com>
[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         g_debug ("ALPHA_DEBUG: %s is called.", x);
26
27 /*========================= End of Defines =========================*/
28
29 /*------------------------------------------------------------------*/
30 /*                 I n c l u d e s                                  */
31 /*------------------------------------------------------------------*/
32
33 #include <config.h>
34 #include <glib.h>
35 #include <string.h>
36
37 #include <mono/metadata/appdomain.h>
38 #include <mono/metadata/marshal.h>
39 #include <mono/metadata/tabledefs.h>
40 #include <mono/arch/alpha/alpha-codegen.h>
41 #include <mono/metadata/mono-debug-debugger.h>
42
43 #include "mini.h"
44 #include "mini-alpha.h"
45
46 /*========================= End of Includes ========================*/
47
48 /*------------------------------------------------------------------*/
49 /*                 T y p e d e f s                                  */
50 /*------------------------------------------------------------------*/
51
52 /*========================= End of Typedefs ========================*/
53
54 /*------------------------------------------------------------------*/
55 /*                   P r o t o t y p e s                            */
56 /*------------------------------------------------------------------*/
57
58 /*========================= End of Prototypes ======================*/
59
60 /*------------------------------------------------------------------*/
61 /*                 G l o b a l   V a r i a b l e s                  */
62 /*------------------------------------------------------------------*/
63
64
65 /*====================== End of Global Variables ===================*/
66
67 /*------------------------------------------------------------------*/
68 /*                                                                  */
69 /* Name         - mono_arch_create_trampoline_code                            */
70 /*                                                                  */
71 /* Function     - Create the designated type of trampoline according*/
72 /*                to the 'tramp_type' parameter.                    */
73 /*                                                                  */
74 /*
75   This code should expect to be called by tramp stub function
76   On Alpha:
77   - pv points to start of stub function
78   - at points to start of this trampoline
79   - allocate stack to save all regs and lmfs
80   - save regs
81   - fill params for trampoline methods (They expect 4 params)
82   - call trampoline method (by standard call convention (pv + ra))
83   - save return value (r0)
84   - restore saved regs + lmfs
85   - restore stack (don't forget space allocated by stub)
86   - use saved return values as new address to give control to
87   - return or jump to new address (don't expect to return here -
88     don't save return address. RA will be holding return address
89     of original caller of tramp stub function). New address function
90     expect standart calling convention (pv)
91
92 */
93 /*------------------------------------------------------------------*/
94
95 guchar *
96 mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
97 {
98   unsigned int *buf, *code, *tramp;
99   int i, lmf_offset, offset, method_offset, tramp_offset,
100     saved_regs_offset, saved_fpregs_offset, framesize, off;
101   gboolean has_caller;
102   
103   ALPHA_DEBUG("mono_arch_create_trampoline_code");
104   
105   if (tramp_type == MONO_TRAMPOLINE_JUMP)
106     has_caller = FALSE;
107   else
108     has_caller = TRUE;
109   
110   code = buf = mono_global_codeman_reserve (512);
111   
112   framesize = 512 + sizeof (MonoLMF);
113   framesize = (framesize +
114                (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
115   
116   offset = 16;
117   
118   // Expect that generated code is called with 2 parameters
119   // method and tramp (in a0 and a1)
120   
121   // Allocate stack
122   alpha_lda(code, alpha_sp, alpha_sp, -framesize);
123
124   /* store call convention parameters on stack.*/
125   alpha_stq( code, alpha_ra, alpha_sp, 0 ); // ra
126   alpha_stq( code, alpha_fp, alpha_sp, 8 ); // fp
127   
128   // Store all integer regs
129   for (i=0; i<30 /*alpha_pc*/; i++)
130     {
131       alpha_stq(code, i, alpha_sp, offset);
132       offset += 8;
133     }
134   
135   // Store all fp regs (TODO)
136
137   /* set the frame pointer */
138   alpha_mov1( code, alpha_sp, alpha_fp );
139   
140   /* Arg3 is the method/vtable ptr */
141   alpha_ldq(code, alpha_a2, alpha_sp, framesize);
142   //alpha_mov1(code, alpha_a0, alpha_a2);
143   
144   /* Arg4 is the trampoline address */
145   alpha_mov1(code, alpha_pv, alpha_a3);
146   //alpha_mov1(code, alpha_a1, alpha_a3);
147   
148   /* Arg1 is the pointer to the saved registers */
149   alpha_lda(code, alpha_a0, alpha_sp, 16);
150   
151   /* Arg2 is the address of the calling code */
152   if (has_caller)
153     alpha_mov1(code, alpha_ra, alpha_a1);
154   else
155     alpha_mov1(code, alpha_zero, alpha_a1);
156   
157   /* Arg3 is the method/vtable ptr 
158      alpha_mov1(code, alpha_a0, alpha_a2);
159      
160      Arg4 is the trampoline address
161      alpha_mov1(code, alpha_a1, alpha_a3);
162   */
163   
164   if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
165     tramp = (unsigned int*)mono_class_init_trampoline;
166   else if (tramp_type == MONO_TRAMPOLINE_AOT)
167     tramp = (unsigned int*)mono_aot_trampoline;
168   else if (tramp_type == MONO_TRAMPOLINE_DELEGATE)
169     tramp = (unsigned int*)mono_delegate_trampoline;
170   else
171     tramp = (unsigned int*)mono_magic_trampoline;
172   
173   off = (char *)code - (char *)buf;
174   off += 2*4;
175   
176   if (off % 8)
177     {
178       alpha_nop(code);
179       off += 4;
180     }
181   
182   // alpha_at points to start of this method !!!
183   alpha_ldq(code, alpha_pv, alpha_at, off);
184   alpha_br(code, alpha_zero, 2);
185   
186   *code = (unsigned int)(((unsigned long)tramp) & 0xFFFFFFFF);
187   code++;
188   *code = (unsigned int)((((unsigned long)tramp) >> 32) & 0xFFFFFFFF);
189   code++;
190   
191   alpha_jsr(code, alpha_ra, alpha_pv, 0);
192   
193   alpha_stq(code, alpha_r0, alpha_sp, framesize);
194   
195   /* Restore LMF */
196   
197   offset = 16;
198   
199   // Restore all integer regs
200   for (i=0; i<30 /*alpha_pc*/; i++)
201     {
202       alpha_ldq(code, i, alpha_sp, offset);
203       offset += 8;
204     }
205   
206   alpha_ldq(code, alpha_r0, alpha_sp, framesize);
207   
208   // Restore stack
209   alpha_lda(code, alpha_sp, alpha_sp, framesize+16);
210   
211   if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
212     alpha_ret (code, alpha_ra, 1);
213   else
214     {
215       /* call the compiled method */
216       // It will expect correct call frame 
217       
218       alpha_mov1(code, alpha_r0, alpha_pv);
219       alpha_jsr (code, alpha_zero, alpha_pv, 0);
220     }
221   
222   g_assert (((char *)code - (char *)buf) <= 512);
223   
224   mono_arch_flush_icache (buf, (char *)code - (char *)buf);
225   
226   return buf;
227 }
228
229 /*========================= End of Function ========================*/
230
231 /*------------------------------------------------------------------*/
232 /*                                                                  */
233 /* Name         - mono_arch_create_jit_trampoline                   */
234 /*                                                                  */
235 /* Function     - Creates a trampoline function for virtual methods.*/
236 /*                If the created code is called it first starts JIT */
237 /*                compilation and then calls the newly created      */
238 /*                method. It also replaces the corresponding vtable */
239 /*                entry (see s390_magic_trampoline).                */
240 /*                                                                  */
241 /*                A trampoline consists of two parts: a main        */
242 /*                fragment, shared by all method trampolines, and   */
243 /*                and some code specific to each method, which      */
244 /*                hard-codes a reference to that method and then    */
245 /*                calls the main fragment.                          */
246 /*                                                                  */
247 /*                The main fragment contains a call to              */
248 /*                's390_magic_trampoline', which performs a call    */
249 /*                to the JIT compiler and substitutes the method-   */
250 /*                specific fragment with some code that directly    */
251 /*                calls the JIT-compiled method.                    */
252 /*                                                                  */
253 /* Parameter    - method - Pointer to the method information        */
254 /*                                                                  */
255 /* Returns      - A pointer to the newly created code               */
256 /*                                                                  */
257 /*------------------------------------------------------------------*/
258
259 gpointer
260 mono_arch_create_jit_trampoline (MonoMethod *method)
261 {
262         ALPHA_DEBUG("mono_arch_create_jit_trampoline: check MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE define");
263
264 //      NOT_IMPLEMENTED("mono_arch_create_jit_trampoline: check MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE define");
265
266         return 0;
267 }
268
269 /*========================= End of Function ========================*/
270
271 /*------------------------------------------------------------------*/
272 /*                                                                  */
273 /* Name         - mono_arch_create_jump_trampoline                  */
274 /*                                                                  */
275 /* Function     - Create the designated type of trampoline according*/
276 /*                to the 'tramp_type' parameter.                    */
277 /*                                                                  */
278 /*------------------------------------------------------------------*/
279
280 MonoJitInfo *
281 mono_arch_create_jump_trampoline (MonoMethod *method)
282 {
283         ALPHA_DEBUG("mono_arch_create_jump_trampoline");
284
285         NOT_IMPLEMENTED("mono_arch_create_jump_trampoline");
286         
287         return 0;
288 }
289
290 /*========================= End of Function ========================*/
291
292 /*------------------------------------------------------------------*/
293 /*                                                                  */
294 /* Name         - mono_arch_create_specific_trampoline              */
295 /*                                                                  */
296 /* Function     - ???Create the designated type of trampoline according*/
297 /*                to the 'tramp_type' parameter.                    */
298 /*                                                                  */
299 /* This method should create a stub code that will transfer
300    control to corresponding trampoline. We need to pass "arg1" and
301    start address of this stab method to trampoline code.
302    We should not modify any registers!!!
303    For Alpha:
304    - allocate 2 qword on stack
305    - save stab start address on 8(sp)
306    - save "arg1" on 0(sp)
307    - jump to trampoline code keeping original caller return address
308      in ra
309 */
310 /*------------------------------------------------------------------*/
311
312 #define TRAMPOLINE_SIZE 52
313
314 gpointer
315 mono_arch_create_specific_trampoline (gpointer arg1,
316         MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
317 {
318   unsigned int *code, *buf, *tramp, *real_code;
319   int offset, size, jump_offset;
320   
321   //  ALPHA_DEBUG("mono_arch_create_specific_trampoline");
322   
323   tramp = mono_get_trampoline_code (tramp_type);
324   
325   code = buf = g_alloca (TRAMPOLINE_SIZE);
326   
327   /* push trampoline address */
328   //amd64_lea_membase (code, AMD64_R11, AMD64_RIP, -7);
329   //amd64_push_reg (code, AMD64_R11);
330   
331   // Allocate two qwords on stack
332   alpha_lda(code, alpha_sp, alpha_sp, -16);
333   
334   alpha_stq(code, alpha_pv, alpha_sp, 8);
335   
336   // Load arg1 into alpha_at
337   offset = (char *)code - (char *)buf;
338   offset += 2*4;
339   if (offset % 8)
340     {
341       alpha_nop(code);
342       offset += 4;
343     }
344   
345   alpha_ldq(code, alpha_at, alpha_pv, offset);
346   alpha_br(code, alpha_zero, 2);
347   
348   *code = (unsigned int)(((unsigned long)arg1) & 0xFFFFFFFF);
349   code++;
350   *code = (unsigned int)((((unsigned long)arg1) >> 32) & 0xFFFFFFFF);
351   code++;
352   
353   // Store arg1 on stack
354   alpha_stq(code, alpha_at, alpha_sp, 0);
355   
356   offset = (char *)code - (char *)buf;
357   offset += 2*4;
358   if (offset % 8)
359     {
360       alpha_nop(code);
361       offset += 4;
362     }
363   
364   alpha_ldq(code, alpha_at, alpha_pv, offset);
365   alpha_br(code, alpha_zero, 2);
366   
367   *code = (unsigned int)(((unsigned long)tramp) & 0xFFFFFFFF);
368   code++;
369   *code = (unsigned int)((((unsigned long)tramp) >> 32) & 0xFFFFFFFF);
370   code++;
371   
372   // Jump to trampoline
373   alpha_jmp(code, alpha_zero, alpha_at, 0);
374   
375   
376   /* push argument */
377   //if (amd64_is_imm32 ((gint64)arg1))
378   //        amd64_push_imm (code, (gint64)arg1);
379   //else {
380   //        amd64_mov_reg_imm (code, AMD64_R11, arg1);
381   //        amd64_push_reg (code, AMD64_R11);
382   //}
383   
384   // jump_offset = code - buf;
385   //amd64_jump_disp (code, 0xffffffff);
386   
387   g_assert (((char *)code - (char *)buf) <= TRAMPOLINE_SIZE);
388   mono_domain_lock (domain);
389   /*
390    * FIXME: Changing the size to code - buf causes strange crashes during
391    * mcs bootstrap.
392    */
393   real_code = mono_code_manager_reserve (domain->code_mp, TRAMPOLINE_SIZE);
394   size = (char *)code - (char *)buf;
395   mono_domain_unlock (domain);
396   
397   memcpy (real_code, buf, size);
398   
399   printf("mono_arch_create_specific_trampoline: Target: %p, Arg1: %p\n",
400          real_code, arg1);
401   
402   /* Fix up jump */
403   //g_assert ((((gint64)tramp) >> 32) == 0);
404   //code = (guint8*)real_code + jump_offset;
405   //amd64_jump_disp (code, tramp - code);
406   
407   mono_jit_stats.method_trampolines++;
408   
409   if (code_len)
410     *code_len = size;
411   
412   mono_arch_flush_icache (real_code, size);
413   
414   return real_code;
415 }
416 /*========================= End of Function ========================*/
417
418 void
419 mono_arch_nullify_class_init_trampoline (guint8 *code, gssize *regs)
420 {
421   ALPHA_DEBUG("mono_arch_nullify_class_init_trampoline");
422 }
423
424
425 void
426 mono_arch_patch_delegate_trampoline (guint8 *code, guint8 *tramp,
427                                      gssize *regs, guint8 *addr)
428 {
429   ALPHA_DEBUG("mono_arch_patch_delegate_trampoline");
430 }
431
432 void
433 mono_arch_patch_callsite (guint8 *code, guint8 *addr)
434 {
435   unsigned long *p = (unsigned int *)(code-12);
436   
437   unsigned int *pcode = (unsigned int *)code;
438   unsigned long gp = pcode;
439   unsigned int call_addr_inst;
440   short high_offset, low_offset;
441
442   ALPHA_DEBUG("mono_arch_patch_callsite");
443
444   // Code points to the next instruction after the "jsr"
445   // In current implementation where we put jump addresses
446   // inside the code - we need to put "new" address into
447   // "code-12"
448
449   // With new method of using GOT we need to find address
450   // where function address is stored
451   // code points to two insts:
452   // ldah gp, high_offset(ra)
453   // lda gp, low_offset(gp)
454   // 
455
456   high_offset = *((short *)pcode);
457   low_offset = *((short *)(pcode + 1));
458
459   gp += 65536 * high_offset + low_offset;
460
461   call_addr_inst = *(pcode - 2);
462
463   // Check for load address instruction
464   // It should be ldq t12, offset(gp)
465   if ((call_addr_inst & 0xFFFF0000) == 0xA77D0000)
466   {
467     gp += *((short *)(pcode - 2));
468
469     p = gp;
470
471     printf("Patch callsite at %p to %p\n", p, addr);
472
473     // TODO - need to to interlocked update here
474     *p = (unsigned long)addr;
475   }
476 }
477
478 /*
479  * mono_arch_get_unbox_trampoline:
480  * @m: method pointer
481  * @addr: pointer to native code for @m
482  *
483  * when value type methods are called through the vtable we need to unbox the
484  * this argument. This method returns a pointer to a trampoline which does
485  * unboxing before calling the method
486  */
487 gpointer
488 mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
489 {
490   ALPHA_DEBUG("mono_arch_get_unbox_trampoline");
491
492   return 0;
493 }
494
495 void
496 mono_arch_nullify_plt_entry (guint8 *code)
497 {
498         g_assert_not_reached ();
499 }
500
501 void
502 mono_arch_patch_plt_entry (guint8 *code, guint8 *addr)
503 {
504         g_assert_not_reached ();
505 }
506