updating to the latest module.
[mono.git] / mono / arch / alpha / tramp.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Create trampolines to invoke arbitrary functions.
4  * 
5  * Copyright (C) Ximian Inc.
6  *
7  * Authors: Laramie Leavitt (lar@leavitt.us)
8  *
9  *
10  */
11
12 /* A typical Alpha stack frame looks like this */
13 /*
14 fun:                         // called from outside the module.
15         ldgp gp,0(pv)        // load the global pointer
16 fun..ng:                     // called from inside the module.
17         lda sp, -SIZE( sp )  // grow the stack downwards.
18
19         stq ra, 0(sp)        // save the return address.
20
21         stq s0, 8(sp)        // callee-saved registers.
22         stq s1, 16(sp)       // ...
23
24         // Move the arguments to the argument registers...
25         
26         mov addr, pv         // Load the callee address
27         jsr  ra, (pv)        // call the method.
28         ldgp gp, 0(ra)       // restore gp
29
30         // return value is in v0
31         
32         ldq ra, 0(sp)        // free stack frame
33         ldq s0, 8(sp)        // restore callee-saved registers.
34         ldq s1, 16(sp)       
35         ldq sp, 32(sp)       // restore stack pointer
36
37         ret zero, (ra), 1    // return.
38
39 // min SIZE = 48
40 // our call must look like this.
41
42 call_func:
43         ldgp gp, 0(pv)
44 call_func..ng:
45         .prologue
46         lda sp, -SIZE(sp)  // grow stack SIZE bytes.
47         stq ra, SIZE-48(sp)   // store ra
48         stq fp, SIZE-40(sp)   // store fp (frame pointer)        
49         stq a0, SIZE-32(sp)   // store args. a0 = func
50         stq a1, SIZE-24(sp)   // a1 = retval
51         stq a2, SIZE-16(sp)   // a2 = this
52         stq a3, SIZE-8(sp)    // a3 = args
53         mov sp, fp            // set frame pointer
54         mov pv, a0            // func
55         
56         .calling_arg_this       
57         mov a1, a2
58         
59         .calling_arg_6plus      
60         ldq t0, POS(a3)
61         stq t0, 0(sp)        
62         ldq t1, POS(a3)
63         stq t1, 8(sp)        
64         ... SIZE-56 ...
65
66         mov zero,a1
67         mov zero,a2
68         mov zero,a3
69         mov zero,a4
70         mov zero,a5
71         
72         .do_call
73         jsr ra, (pv)    // call func
74         ldgp gp, 0(ra)  // restore gp.
75         mov v0, t1      // move return value into t1
76         
77         .do_store_retval
78         ldq t0, SIZE-24(fp) // load retval into t2
79         stl t1, 0(t0)       // store value.
80
81         .finished       
82         mov fp,sp
83         ldq ra,SIZE-48(sp)
84         ldq fp,SIZE-40(sp)
85         lda sp,SIZE(sp)
86         ret zero,(ra),1
87                         
88         
89 */
90 /*****************************************************/
91
92 #include "config.h"
93 #include <stdlib.h>
94 #include <string.h>
95
96 #include "alpha-codegen.h"
97
98 #include "mono/metadata/class.h"
99 #include "mono/metadata/tabledefs.h"
100 #include "mono/interpreter/interp.h"
101 #include "mono/metadata/appdomain.h"
102 #include "mono/metadata/debug-helpers.h"
103
104 #define AXP_GENERAL_REGS     6
105 #define AXP_MIN_STACK_SIZE   24
106 #define ARG_SIZE   sizeof(stackval)
107 #define ARG_LOC(x) (x * sizeof( stackval ) )
108
109 /*****************************************************/
110
111 /*                                                                  */
112 /*                void func (void (*callme)(), void *retval,        */
113 /*                           void *this_obj, stackval *arguments);  */
114 static inline guint8 *
115 emit_prolog (guint8 *p, const gint SIZE, int hasthis )
116 {
117         // 9 instructions.
118         alpha_ldah( p, alpha_gp, alpha_pv, 0 );  
119         alpha_lda( p, alpha_sp, alpha_sp, -SIZE ); // grow stack down SIZE
120         alpha_lda( p, alpha_gp, alpha_gp, 0 );     // ldgp gp, 0(pv)
121         
122         /* TODO: we really don't need to store everything.
123            alpha_a1: We have to store this in order to return the retval.
124            
125            alpha_a0: func pointer can be moved directly to alpha_pv
126            alpha_a3: don't need args after we are finished.
127            alpha_a2: will be moved into alpha_a0... if hasthis is true.
128         */
129         /* store parameters on stack.*/
130         alpha_stq( p, alpha_ra, alpha_sp, SIZE-24 ); // ra
131         alpha_stq( p, alpha_fp, alpha_sp, SIZE-16 ); // fp
132         alpha_stq( p, alpha_a1, alpha_sp, SIZE-8 );  // retval
133         
134         /* set the frame pointer */
135         alpha_mov1( p, alpha_sp, alpha_fp );
136        
137         /* move the args into t0, pv */
138         alpha_mov1( p, alpha_a0, alpha_pv );
139         alpha_mov1( p, alpha_a3, alpha_t0 );
140
141         // Move the this pointer into a0.       
142         if( hasthis )
143             alpha_mov1( p, alpha_a2, alpha_a0 );
144         return p;
145 }
146
147 static inline guint8 *
148 emit_call( guint8 *p , const gint SIZE )
149 {
150         // 3 instructions
151         /* call func */
152         alpha_jsr( p, alpha_ra, alpha_pv, 0 );     // jsr ra, 0(pv)
153
154         /* reload the gp */
155         alpha_ldah( p, alpha_gp, alpha_ra, 0 );  
156         alpha_lda( p, alpha_gp, alpha_gp, 0 );     // ldgp gp, 0(ra)
157         
158         return p;
159 }
160
161 static inline guint8 *
162 emit_store_return_default(guint8 *p, const gint SIZE )
163 {
164         // 2 instructions.
165         
166         /* TODO: This probably do different stuff based on the value.  
167            you know, like stq/l/w. and s/f.
168         */
169         alpha_ldq( p, alpha_t0, alpha_fp, SIZE-8 );  // load void * retval
170         alpha_stq( p, alpha_v0, alpha_t0, 0 );       // store the result to *retval.
171         return p;
172 }
173
174
175 static inline guint8 *
176 emit_epilog (guint8 *p, const gint SIZE )
177 {       
178         // 5 instructions.
179         alpha_mov1( p, alpha_fp, alpha_sp );
180
181         /* restore fp, ra, sp */
182         alpha_ldq( p, alpha_ra, alpha_sp, SIZE-24 ); 
183         alpha_ldq( p, alpha_fp, alpha_sp, SIZE-16 ); 
184         alpha_lda( p, alpha_sp, alpha_sp, SIZE ); 
185         
186         /* return */
187         alpha_ret( p, alpha_ra, 1 );
188         return p;
189 }
190
191 static void calculate_size(MonoMethodSignature *sig, int * INSTRUCTIONS, int * STACK )
192 {
193         int alpharegs;
194         
195         alpharegs = AXP_GENERAL_REGS - (sig->hasthis?1:0);
196
197         *STACK        = AXP_MIN_STACK_SIZE;
198         *INSTRUCTIONS = 20;  // Base: 20 instructions.
199         
200         if( sig->param_count - alpharegs > 0 )
201         {
202                 *STACK += ARG_SIZE * (sig->param_count - alpharegs );
203                 // plus 3 (potential) for each stack parameter. 
204                 *INSTRUCTIONS += ( sig->param_count - alpharegs ) * 3;
205                 // plus 2 (potential) for each register parameter. 
206                 *INSTRUCTIONS += ( alpharegs * 2 );
207         }
208         else
209         {
210                 // plus 2 (potential) for each register parameter. 
211                 *INSTRUCTIONS += ( sig->param_count * 2 );
212         }
213 }
214
215 MonoPIFunc
216 mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
217 {
218         unsigned char *p;
219         unsigned char *buffer;
220         MonoType* param;
221
222         int i, pos;
223         int alpharegs;
224         int hasthis;
225         int STACK_SIZE;
226         int BUFFER_SIZE;
227         int simple_type;
228         int regbase;
229         
230         // Set up basic stuff.  like has this.  
231         hasthis = !!sig->hasthis;
232         alpharegs = AXP_GENERAL_REGS - hasthis;
233         regbase  = hasthis?alpha_a1:alpha_a0 ;
234         
235         // Make a ballpark estimate for now.
236         calculate_size( sig, &BUFFER_SIZE, &STACK_SIZE );
237         
238         // convert to the correct number of bytes.
239         BUFFER_SIZE = BUFFER_SIZE * 4;
240
241         
242         // allocate.    
243         buffer = p = malloc(BUFFER_SIZE);
244         memset( buffer, 0, BUFFER_SIZE );
245         pos = 0;
246         
247         // Ok, start creating this thing.
248         p = emit_prolog( p, STACK_SIZE, hasthis );
249
250         // copy everything into the correct register/stack space
251         for (i = sig->param_count; --i >= 0; ) 
252         {
253                 param = sig->params [i];
254                 
255                 if( param->byref )
256                 {
257                         if( i > alpharegs )
258                         {
259                                 // load into temp register, then store on the stack 
260                                 alpha_ldq( p, alpha_t1, alpha_t0, ARG_LOC( i ));
261                                 alpha_stl( p, alpha_t1, alpha_sp, pos );
262                                 pos += 8;
263                                 
264                                 if( pos > 128 )
265                                         g_error( "Too large." );
266                         }
267                         else
268                         {
269                                 // load into register
270                                 alpha_ldq( p, regbase + i, alpha_t0, ARG_LOC( i ) );
271                         }
272                 }
273                 else
274                 {
275                         simple_type = param->type;
276                         if( simple_type == MONO_TYPE_VALUETYPE )
277                         {
278                                 if (sig->ret->data.klass->enumtype)
279                                         simple_type = sig->ret->data.klass->enum_basetype->type;
280                         }
281                         
282                         switch (simple_type) 
283                         {
284                         case MONO_TYPE_VOID:
285                                 break;
286                         case MONO_TYPE_BOOLEAN:
287                         case MONO_TYPE_CHAR:
288                         case MONO_TYPE_I1:
289                         case MONO_TYPE_U1:
290                         case MONO_TYPE_I2:
291                         case MONO_TYPE_U2:
292                         case MONO_TYPE_I4:
293                         case MONO_TYPE_U4:
294                         case MONO_TYPE_I:
295                         case MONO_TYPE_U:
296                         case MONO_TYPE_PTR:
297                         case MONO_TYPE_CLASS:
298                         case MONO_TYPE_OBJECT:
299                         case MONO_TYPE_STRING:
300                         case MONO_TYPE_I8:
301                                 // 8 bytes
302                                 if( i > alpharegs )
303                                 {
304                                         // load into temp register, then store on the stack
305                                         alpha_ldq( p, alpha_t1, alpha_t0, ARG_LOC( i ) );
306                                         alpha_stq( p, alpha_t1, alpha_sp, pos );
307                                         pos += 8;
308                                 }
309                                 else
310                                 {
311                                         // load into register
312                                         alpha_ldq( p, regbase + i, alpha_t0, ARG_LOC(i) );
313                                 }
314                                 break;
315                         case MONO_TYPE_R4:
316                         case MONO_TYPE_R8:
317                                 /*
318                                 // floating point... Maybe this does the correct thing.
319                                 if( i > alpharegs )
320                                 {
321                                         alpha_ldq( p, alpha_t1, alpha_t0, ARG_LOC( i ) );
322                                         alpha_cpys( p, alpha_ft1, alpha_ft1, alpha_ft2 );
323                                         alpha_stt( p, alpha_ft2, alpha_sp, pos );
324                                         pos += 8;
325                                 }
326                                 else
327                                 {
328                                         alpha_ldq( p, alpha_t1, alpha_t0, ARG_LOC(i) );
329                                         alpha_cpys( p, alpha_ft1, alpha_ft1, alpha_fa0 + i + hasthis );
330                                 }
331                                 break;
332                                 */
333                         case MONO_TYPE_VALUETYPE:
334                                 g_error ("Not implemented: ValueType as parameter to delegate." );
335                                 break;
336                         default:
337                                 g_error( "Not implemented." );
338                                 break;  
339                         }
340                 }
341         }
342         
343         // Now call the function and store the return parameter.
344         p = emit_call( p, STACK_SIZE );
345         p = emit_store_return_default( p, STACK_SIZE );
346         p = emit_epilog( p, STACK_SIZE );
347
348         if( p > buffer + BUFFER_SIZE )
349                 g_error( "Buffer overflow." );
350         
351         return (MonoPIFunc)buffer;
352 }
353
354 void *
355 mono_arch_create_method_pointer (MonoMethod *method)
356 {
357         g_error ("Unsupported arch");
358         return NULL;
359 }