1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Create trampolines to invoke arbitrary functions.
5 * Copyright (C) Ximian Inc.
7 * Authors: Laramie Leavitt (lar@leavitt.us)
12 /* A typical Alpha stack frame looks like this */
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.
19 stq ra, 0(sp) // save the return address.
21 stq s0, 8(sp) // callee-saved registers.
24 // Move the arguments to the argument registers...
26 mov addr, pv // Load the callee address
27 jsr ra, (pv) // call the method.
28 ldgp gp, 0(ra) // restore gp
30 // return value is in v0
32 ldq ra, 0(sp) // free stack frame
33 ldq s0, 8(sp) // restore callee-saved registers.
35 ldq sp, 32(sp) // restore stack pointer
37 ret zero, (ra), 1 // return.
40 // our call must look like this.
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
73 jsr ra, (pv) // call func
74 ldgp gp, 0(ra) // restore gp.
75 mov v0, t1 // move return value into t1
78 ldq t0, SIZE-24(fp) // load retval into t2
79 stl t1, 0(t0) // store value.
90 /*****************************************************/
96 #include "alpha-codegen.h"
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"
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 ) )
109 /*****************************************************/
112 /* void func (void (*callme)(), void *retval, */
113 /* void *this_obj, stackval *arguments); */
114 static inline unsigned int *
115 emit_prolog (unsigned int *pi, const gint SIZE, int hasthis )
117 unsigned int *p = (unsigned int *)pi;
119 alpha_ldah( p, alpha_gp, alpha_pv, 0 );
120 alpha_lda( p, alpha_gp, alpha_gp, 0 ); // ldgp gp, 0(pv)
121 alpha_lda( p, alpha_sp, alpha_sp, -((SIZE & 8) ? (SIZE+8) : SIZE) ); // grow stack down SIZE (align to 16 bytes like gcc does)
123 /* TODO: we really don't need to store everything.
124 alpha_a1: We have to store this in order to return the retval.
126 alpha_a0: func pointer can be moved directly to alpha_pv
127 alpha_a3: don't need args after we are finished.
128 alpha_a2: will be moved into alpha_a0... if hasthis is true.
130 /* store parameters on stack.*/
131 alpha_stq( p, alpha_ra, alpha_sp, (SIZE-24) ); // ra
132 alpha_stq( p, alpha_fp, alpha_sp, (SIZE-16) ); // fp
133 alpha_stq( p, alpha_a1, alpha_sp, (SIZE-8) ); // retval
135 /* set the frame pointer */
136 alpha_mov1( p, alpha_sp, alpha_fp );
138 /* move the args into t0, pv */
139 alpha_mov1( p, alpha_a0, alpha_pv );
140 alpha_mov1( p, alpha_a3, alpha_t0 );
142 // Move the this pointer into a0.
144 alpha_mov1( p, alpha_a2, alpha_a0 );
148 static inline unsigned int *
149 emit_call( unsigned int *pi , const gint SIZE )
151 unsigned int *p = (unsigned int *)pi;
155 alpha_jsr( p, alpha_ra, alpha_pv, 0 ); // jsr ra, 0(pv)
158 alpha_ldah( p, alpha_gp, alpha_ra, 0 );
159 alpha_lda( p, alpha_gp, alpha_gp, 0 ); // ldgp gp, 0(ra)
164 static inline unsigned int *
165 emit_store_return_default(unsigned int *pi, const gint SIZE )
168 unsigned int *p = (unsigned int *)pi;
170 /* TODO: This probably do different stuff based on the value.
171 you know, like stq/l/w. and s/f.
173 alpha_ldq( p, alpha_t0, alpha_fp, (SIZE-8) ); // load void * retval
174 alpha_stq( p, alpha_v0, alpha_t0, 0 ); // store the result to *retval.
179 static inline unsigned int *
180 emit_epilog (unsigned int *pi, const gint SIZE )
182 unsigned int *p = (unsigned int *)pi;
185 alpha_mov1( p, alpha_fp, alpha_sp );
187 /* restore fp, ra, sp */
188 alpha_ldq( p, alpha_ra, alpha_sp, (SIZE-24) );
189 alpha_ldq( p, alpha_fp, alpha_sp, (SIZE-16) );
190 alpha_lda( p, alpha_sp, alpha_sp, ((SIZE & 8) ? (SIZE+8) : SIZE) );
193 alpha_ret( p, alpha_ra, 1 );
197 static void calculate_size(MonoMethodSignature *sig, int * INSTRUCTIONS, int * STACK )
201 alpharegs = AXP_GENERAL_REGS - (sig->hasthis?1:0);
203 *STACK = AXP_MIN_STACK_SIZE;
204 *INSTRUCTIONS = 20; // Base: 20 instructions.
206 if( sig->param_count - alpharegs > 0 )
208 *STACK += ARG_SIZE * (sig->param_count - alpharegs );
209 // plus 3 (potential) for each stack parameter.
210 *INSTRUCTIONS += ( sig->param_count - alpharegs ) * 3;
211 // plus 2 (potential) for each register parameter.
212 *INSTRUCTIONS += ( alpharegs * 2 );
216 // plus 2 (potential) for each register parameter.
217 *INSTRUCTIONS += ( sig->param_count * 2 );
222 mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
225 unsigned int *buffer;
236 // Set up basic stuff. like has this.
237 hasthis = !!sig->hasthis;
238 alpharegs = AXP_GENERAL_REGS - hasthis;
239 regbase = hasthis?alpha_a1:alpha_a0 ;
241 // Make a ballpark estimate for now.
242 calculate_size( sig, &BUFFER_SIZE, &STACK_SIZE );
244 // convert to the correct number of bytes.
245 BUFFER_SIZE = BUFFER_SIZE * 4;
249 buffer = p = (unsigned int *)malloc(BUFFER_SIZE);
250 memset( buffer, 0, BUFFER_SIZE );
251 pos = 8 * (sig->param_count - alpharegs - 1);
253 // Ok, start creating this thing.
254 p = emit_prolog( p, STACK_SIZE, hasthis );
256 // copy everything into the correct register/stack space
257 for (i = sig->param_count; --i >= 0; )
259 param = sig->params [i];
265 // load into temp register, then store on the stack
266 alpha_ldq( p, alpha_t1, alpha_t0, ARG_LOC( i ));
267 alpha_stq( p, alpha_t1, alpha_sp, pos );
272 // load into register
273 alpha_ldq( p, (regbase + i), alpha_t0, ARG_LOC( i ) );
278 simple_type = param->type;
279 if( simple_type == MONO_TYPE_VALUETYPE )
281 if (param->data.klass->enumtype)
282 simple_type = param->data.klass->enum_basetype->type;
289 case MONO_TYPE_BOOLEAN:
297 // 4 bytes - need to sign-extend (stackvals are not extended)
300 // load into temp register, then store on the stack
301 alpha_ldl( p, alpha_t1, alpha_t0, ARG_LOC( i ) );
302 alpha_stq( p, alpha_t1, alpha_sp, pos );
307 // load into register
308 alpha_ldl( p, (regbase + i), alpha_t0, (ARG_LOC(i)) );
314 case MONO_TYPE_CLASS:
315 case MONO_TYPE_OBJECT:
316 case MONO_TYPE_SZARRAY:
317 case MONO_TYPE_STRING:
322 // load into temp register, then store on the stack
323 alpha_ldq( p, alpha_t1, alpha_t0, ARG_LOC( i ) );
324 alpha_stq( p, alpha_t1, alpha_sp, pos );
329 // load into register
330 alpha_ldq( p, (regbase + i), alpha_t0, ARG_LOC(i) );
336 // floating point... Maybe this does the correct thing.
339 alpha_ldq( p, alpha_t1, alpha_t0, ARG_LOC( i ) );
340 alpha_cpys( p, alpha_ft1, alpha_ft1, alpha_ft2 );
341 alpha_stt( p, alpha_ft2, alpha_sp, pos );
346 alpha_ldq( p, alpha_t1, alpha_t0, ARG_LOC(i) );
347 alpha_cpys( p, alpha_ft1, alpha_ft1, alpha_fa0 + i + hasthis );
351 case MONO_TYPE_VALUETYPE:
352 g_error ("Not implemented: ValueType as parameter to delegate." );
355 g_error( "Not implemented: 0x%x.", simple_type );
361 // Now call the function and store the return parameter.
362 p = emit_call( p, STACK_SIZE );
363 p = emit_store_return_default( p, STACK_SIZE );
364 p = emit_epilog( p, STACK_SIZE );
366 if( p > buffer + BUFFER_SIZE )
367 g_error( "Buffer overflow: got 0x%lx, expected <=0x%x.", (long)(p-buffer), BUFFER_SIZE );
369 /* flush instruction cache to see trampoline code */
370 asm volatile("imb":::"memory");
372 return (MonoPIFunc)buffer;
376 mono_arch_create_method_pointer (MonoMethod *method)
378 g_error ("Unsupported arch");