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 ** This method is called after delegate method is compiled.
515 ** We need to patch call site to call compiled method directly
516 ** (not via trampoline stub)
517 ** Determine address to patch using fp reg
518 ** 
519 */
520
521 void
522 mono_arch_patch_delegate_trampoline (guint8 *code, guint8 *tramp,
523                                      gssize *regs, guint8 *addr)
524 {
525   unsigned int *pcode = (unsigned int *)code;
526   int reg;
527   short fp_disp, obj_disp;
528   unsigned long *pobj, obj;
529
530   ALPHA_DEBUG("mono_arch_patch_delegate_trampoline");
531
532   // The call signature for now is
533   // -4 - ldq     v0,24(fp)
534   // -3 - ldq     v0,40(v0)
535   // -2 - mov     v0,t12
536   // -1 - jsr     ra,(t12),0x200041476e4
537   //  0 - ldah    gp,0(ra)
538   if (((pcode[-4] & 0xFF000000) == 0xA4000000) &&
539       ((pcode[-3] & 0xFF000000) == 0xA4000000) &&
540       ((pcode[-2] & 0xFF00FF00) == 0x47000400) &&
541       ((pcode[-1] & 0xFFFF0000) == 0x6B5B0000))
542     {
543       fp_disp = (pcode[-4] & 0xFFFF);
544       obj_disp = (pcode[-3] & 0xFFFF);
545
546       pobj = regs[15] + fp_disp;
547       obj = *pobj;
548       reg = 0;
549     }
550   else
551     // The non-optimized call signature for now is
552     // -5 - ldq     v0,24(fp)
553     // -4 - mov     v0,v0
554     // -3 - ldq     v0,40(v0)
555     // -2 - mov     v0,t12
556     // -1 - jsr     ra,(t12),0x200041476e4
557     //  0 - ldah    gp,0(ra)
558     if (((pcode[-5] & 0xFF000000) == 0xA4000000) &&
559         ((pcode[-4] & 0xFF00FF00) == 0x47000400) &&
560         ((pcode[-3] & 0xFF000000) == 0xA4000000) &&
561         ((pcode[-2] & 0xFF00FF00) == 0x47000400) &&
562         ((pcode[-1] & 0xFFFF0000) == 0x6B5B0000))
563       {
564         fp_disp = (pcode[-5] & 0xFFFF);
565         obj_disp = (pcode[-3] & 0xFFFF);
566
567         pobj = regs[15] + fp_disp;
568         obj = *pobj;
569         reg = 0;
570       }
571     else
572       g_assert_not_reached ();
573
574   *((gpointer*)(obj + obj_disp)) = addr;
575 }
576
577 void
578 mono_arch_patch_callsite (guint8 *code, guint8 *addr)
579 {
580   unsigned long *p = (unsigned int *)(code-12);
581   
582   unsigned int *pcode = (unsigned int *)code;
583   unsigned long gp = (unsigned long)pcode;
584   unsigned int call_addr_inst;
585   short high_offset, low_offset;
586
587   ALPHA_DEBUG("mono_arch_patch_callsite");
588
589   // Code points to the next instruction after the "jsr"
590   // In current implementation where we put jump addresses
591   // inside the code - we need to put "new" address into
592   // "code-12"
593
594   // With new method of using GOT we need to find address
595   // where function address is stored
596   // code points to two insts:
597   // ldah gp, high_offset(ra)
598   // lda gp, low_offset(gp)
599   // 
600
601   high_offset = *((short *)pcode);
602   low_offset = *((short *)(pcode + 1));
603
604   gp += 65536 * high_offset + low_offset;
605
606   call_addr_inst = *(pcode - 2);
607
608   // Check for load address instruction
609   // It should be ldq t12, offset(gp)
610   if ((call_addr_inst & 0xFFFF0000) == 0xA77D0000)
611   {
612     gp += *((short *)(pcode - 2));
613
614     p = (unsigned long *)gp;
615
616     ALPHA_PRINT g_debug("Patch callsite at %p to %p\n", p, addr);
617
618     // TODO - need to to interlocked update here
619     *p = (unsigned long)addr;
620   }
621 }
622
623 /*
624  * mono_arch_get_unbox_trampoline:
625  * @m: method pointer
626  * @addr: pointer to native code for @m
627  *
628  * when value type methods are called through the vtable we need to unbox the
629  * this argument. This method returns a pointer to a trampoline which does
630  * unboxing before calling the method
631  */
632 gpointer
633 mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
634 {
635   unsigned int *code, *start_code;
636   int this_reg = 16; //R16
637   int off;
638   MonoDomain *domain = mono_domain_get ();
639
640   ALPHA_DEBUG("mono_arch_get_unbox_trampoline");
641
642   if (!mono_method_signature (m)->ret->byref &&
643       MONO_TYPE_ISSTRUCT (mono_method_signature (m)->ret))
644     this_reg = 17; //R17
645
646   mono_domain_lock (domain);
647   start_code = code = (unsigned int *)mono_code_manager_reserve (domain->code_mp, 32);
648   mono_domain_unlock (domain);
649
650   // Adjust this by size of MonoObject
651   alpha_addq_(code, this_reg, sizeof(MonoObject), this_reg);  // 0
652   alpha_bsr(code, alpha_pv, 2);  // 4
653
654   *code = (unsigned int)(((unsigned long)addr) & 0xFFFFFFFF);
655   code++;
656   *code = (unsigned int)((((unsigned long)addr) >> 32) & 0xFFFFFFFF);
657   code++;
658
659   // Load "addr" into PV (R12)
660   alpha_ldq(code, alpha_pv, alpha_pv, 0);
661
662   // Jump to addr
663   alpha_jsr(code, alpha_zero, alpha_pv, 0);
664
665   g_assert (((char *)code - (char *)start_code) < 32);
666
667   mono_arch_flush_icache (start_code, (char *)code - (char *)start_code);
668
669   return start_code;
670 }
671
672 void
673 mono_arch_nullify_plt_entry (guint8 *code)
674 {
675         g_assert_not_reached ();
676 }
677
678 void
679 mono_arch_patch_plt_entry (guint8 *code, guint8 *addr)
680 {
681         g_assert_not_reached ();
682 }
683
684 /*
685  * This method is only called when running in the Mono Debugger.
686  */
687 guint8 *
688 mono_debugger_create_notification_function (MonoCodeManager *codeman)
689 {
690   guint8 *code;
691   unsigned int *buf;
692
693   code = mono_code_manager_reserve (codeman, 16);
694   buf = (unsigned int *)code;
695
696   *buf = 0;
697
698   alpha_call_pal(buf, 0x80);
699   alpha_ret(buf, alpha_ra, 1);
700   //x86_breakpoint (buf);
701   //x86_ret (buf);
702
703   return code;
704 }
705