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 guint8 *
115 emit_prolog (guint8 *p, const gint SIZE, int hasthis )
118 alpha_ldah( p, alpha_gp, alpha_pv, 0 );
119 alpha_lda( p, alpha_gp, alpha_gp, 0 ); // ldgp gp, 0(pv)
120 alpha_lda( p, alpha_sp, alpha_sp, -((SIZE & 8) ? (SIZE+8) : SIZE) ); // grow stack down SIZE (align to 16 bytes like gcc does)
122 /* TODO: we really don't need to store everything.
123 alpha_a1: We have to store this in order to return the retval.
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.
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
134 /* set the frame pointer */
135 alpha_mov1( p, alpha_sp, alpha_fp );
137 /* move the args into t0, pv */
138 alpha_mov1( p, alpha_a0, alpha_pv );
139 alpha_mov1( p, alpha_a3, alpha_t0 );
141 // Move the this pointer into a0.
143 alpha_mov1( p, alpha_a2, alpha_a0 );
147 static inline guint8 *
148 emit_call( guint8 *p , const gint SIZE )
152 alpha_jsr( p, alpha_ra, alpha_pv, 0 ); // jsr ra, 0(pv)
155 alpha_ldah( p, alpha_gp, alpha_ra, 0 );
156 alpha_lda( p, alpha_gp, alpha_gp, 0 ); // ldgp gp, 0(ra)
161 static inline guint8 *
162 emit_store_return_default(guint8 *p, const gint SIZE )
166 /* TODO: This probably do different stuff based on the value.
167 you know, like stq/l/w. and s/f.
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.
175 static inline guint8 *
176 emit_epilog (guint8 *p, const gint SIZE )
179 alpha_mov1( p, alpha_fp, alpha_sp );
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 & 8) ? (SIZE+8) : SIZE) );
187 alpha_ret( p, alpha_ra, 1 );
191 static void calculate_size(MonoMethodSignature *sig, int * INSTRUCTIONS, int * STACK )
195 alpharegs = AXP_GENERAL_REGS - (sig->hasthis?1:0);
197 *STACK = AXP_MIN_STACK_SIZE;
198 *INSTRUCTIONS = 20; // Base: 20 instructions.
200 if( sig->param_count - alpharegs > 0 )
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 );
210 // plus 2 (potential) for each register parameter.
211 *INSTRUCTIONS += ( sig->param_count * 2 );
216 mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
219 unsigned char *buffer;
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 ;
235 // Make a ballpark estimate for now.
236 calculate_size( sig, &BUFFER_SIZE, &STACK_SIZE );
238 // convert to the correct number of bytes.
239 BUFFER_SIZE = BUFFER_SIZE * 4;
243 buffer = p = malloc(BUFFER_SIZE);
244 memset( buffer, 0, BUFFER_SIZE );
245 pos = 8 * (sig->param_count - alpharegs - 1);
247 // Ok, start creating this thing.
248 p = emit_prolog( p, STACK_SIZE, hasthis );
250 // copy everything into the correct register/stack space
251 for (i = sig->param_count; --i >= 0; )
253 param = sig->params [i];
259 // load into temp register, then store on the stack
260 alpha_ldq( p, alpha_t1, alpha_t0, ARG_LOC( i ));
261 alpha_stq( p, alpha_t1, alpha_sp, pos );
266 // load into register
267 alpha_ldq( p, regbase + i, alpha_t0, ARG_LOC( i ) );
272 simple_type = param->type;
273 if( simple_type == MONO_TYPE_VALUETYPE )
275 if (param->data.klass->enumtype)
276 simple_type = param->data.klass->enum_basetype->type;
283 case MONO_TYPE_BOOLEAN:
291 // 4 bytes - need to sign-extend (stackvals are not extended)
294 // load into temp register, then store on the stack
295 alpha_ldl( p, alpha_t1, alpha_t0, ARG_LOC( i ) );
296 alpha_stq( p, alpha_t1, alpha_sp, pos );
301 // load into register
302 alpha_ldl( p, regbase + i, alpha_t0, ARG_LOC(i) );
308 case MONO_TYPE_CLASS:
309 case MONO_TYPE_OBJECT:
310 case MONO_TYPE_SZARRAY:
311 case MONO_TYPE_STRING:
316 // load into temp register, then store on the stack
317 alpha_ldq( p, alpha_t1, alpha_t0, ARG_LOC( i ) );
318 alpha_stq( p, alpha_t1, alpha_sp, pos );
323 // load into register
324 alpha_ldq( p, regbase + i, alpha_t0, ARG_LOC(i) );
330 // floating point... Maybe this does the correct thing.
333 alpha_ldq( p, alpha_t1, alpha_t0, ARG_LOC( i ) );
334 alpha_cpys( p, alpha_ft1, alpha_ft1, alpha_ft2 );
335 alpha_stt( p, alpha_ft2, alpha_sp, pos );
340 alpha_ldq( p, alpha_t1, alpha_t0, ARG_LOC(i) );
341 alpha_cpys( p, alpha_ft1, alpha_ft1, alpha_fa0 + i + hasthis );
345 case MONO_TYPE_VALUETYPE:
346 g_error ("Not implemented: ValueType as parameter to delegate." );
349 g_error( "Not implemented: 0x%x.", simple_type );
355 // Now call the function and store the return parameter.
356 p = emit_call( p, STACK_SIZE );
357 p = emit_store_return_default( p, STACK_SIZE );
358 p = emit_epilog( p, STACK_SIZE );
360 if( p > buffer + BUFFER_SIZE )
361 g_error( "Buffer overflow: got 0x%lx, expected <=0x%x.", (long)(p-buffer), BUFFER_SIZE );
363 /* flush instruction cache to see trampoline code */
364 asm volatile("imb":::"memory");
366 return (MonoPIFunc)buffer;
370 mono_arch_create_method_pointer (MonoMethod *method)
372 g_error ("Unsupported arch");