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: Paolo Molaro (lupus@ximian.com)
8 * Jeffrey Stedfast <fejj@ximian.com>
14 #include "sparc-codegen.h"
15 #include "mono/metadata/class.h"
16 #include "mono/metadata/tabledefs.h"
17 #include "mono/interpreter/interp.h"
18 #include "mono/metadata/appdomain.h"
21 #define FUNC_ADDR_POS sparc_i0
22 #define RETVAL_POS sparc_i1
23 #define THIS_POS sparc_i2
24 #define ARGP_POS sparc_i3
27 #define ARG_SIZE sizeof (stackval)
30 fake_func (void (*callme)(gpointer, gpointer), stackval *retval, void *this_obj, stackval *arguments)
33 *(gpointer*)retval = (gpointer)(*callme) (arguments [0].data.p, arguments [1].data.p, arguments [2].data.p);
34 *(gdouble*) retval = (gdouble)(*callme) (arguments [0].data.f);
37 /* internal_from_handle() */
38 /* return (gpointer)(*callme) (((MonoType *)arguments [0].data.p)->data.klass); */
40 /* InitializeArray() */
41 (*callme) (arguments [0].data.p, arguments [1].data.p);
49 return "MONO_TYPE_END";
51 return "MONO_TYPE_VOID";
52 case MONO_TYPE_BOOLEAN:
53 return "MONO_TYPE_BOOLEAN";
55 return "MONO_TYPE_CHAR";
57 return "MONO_TYPE_I1";
59 return "MONO_TYPE_U1";
61 return "MONO_TYPE_I2";
63 return "MONO_TYPE_U2";
65 return "MONO_TYPE_I4";
67 return "MONO_TYPE_U4";
69 return "MONO_TYPE_I8";
71 return "MONO_TYPE_U8";
73 return "MONO_TYPE_R4";
75 return "MONO_TYPE_R8";
76 case MONO_TYPE_STRING:
77 return "MONO_TYPE_STRING";
79 return "MONO_TYPE_PTR";
81 return "MONO_TYPE_BYREF";
82 case MONO_TYPE_VALUETYPE:
83 return "MONO_TYPE_VALUETYPE";
85 return "MONO_TYPE_CLASS";
87 return "MONO_TYPE_ARRAY";
88 case MONO_TYPE_TYPEDBYREF:
89 return "MONO_TYPE_TYPEBYREF";
95 return "MONO_TYPE_FNPTR";
96 case MONO_TYPE_OBJECT:
97 return "MONO_TYPE_OBJECT";
98 case MONO_TYPE_SZARRAY:
99 return "MONO_TYPE_SZARRAY";
100 case MONO_TYPE_CMOD_REQD:
101 return "MONO_TYPE_CMOD_REQD";
102 case MONO_TYPE_CMOD_OPT:
103 return "MONO_TYPE_CMOD_OPT";
104 case MONO_TYPE_INTERNAL:
105 return "MONO_TYPE_INTERNAL";
106 case MONO_TYPE_MODIFIER:
107 return "MONO_TYPE_MODIFIER";
108 case MONO_TYPE_SENTINEL:
109 return "MONO_TYPE_SENTINEL";
110 case MONO_TYPE_PINNED:
111 return "MONO_TYPE_PINNED";
118 calculate_sizes (MonoMethod *method, guint32 *local_size, guint32 *stack_size, guint32 *code_size, int runtime)
120 MonoMethodSignature *sig = method->signature;
121 guint32 local = 0, stack = 0, code = 6;
125 /* function arguments */
129 for (i = 0; i < sig->param_count; i++) {
130 if (sig->params[i]->byref) {
131 stack += sizeof (gpointer);
132 code += i < 6 ? 1 : 3;
136 simpletype = sig->params[i]->type;
138 switch (simpletype) {
139 case MONO_TYPE_BOOLEAN:
151 case MONO_TYPE_SZARRAY:
152 case MONO_TYPE_CLASS:
153 case MONO_TYPE_OBJECT:
155 code += i < 6 ? 1 : 3;
157 case MONO_TYPE_VALUETYPE:
158 if (sig->params[i]->data.klass->enumtype) {
159 simpletype = sig->params[i]->data.klass->enum_basetype->type;
162 if (mono_class_value_size (sig->params[i]->data.klass, NULL) != 4)
163 g_error ("can only marshal enums, not generic structures (size: %d)",
164 mono_class_value_size (sig->params[i]->data.klass, NULL));
166 code += i < 6 ? 1 : 3;
168 case MONO_TYPE_STRING:
169 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
171 code += i < 6 ? 1 : 3;
181 code += i < 6 ? 2 : 3;
185 code += i < 6 ? 2 : 3;
188 g_error ("Can't trampoline 0x%x", sig->params[i]->type);
192 /* function return value */
193 if (sig->ret->byref) {
196 simpletype = sig->ret->type;
198 switch (simpletype) {
199 case MONO_TYPE_BOOLEAN:
209 case MONO_TYPE_CLASS:
210 case MONO_TYPE_OBJECT:
213 case MONO_TYPE_SZARRAY:
214 case MONO_TYPE_ARRAY:
218 case MONO_TYPE_STRING:
220 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && !runtime) {
228 case MONO_TYPE_VALUETYPE:
229 if (sig->ret->data.klass->enumtype) {
230 simpletype = sig->ret->data.klass->enum_basetype->type;
238 g_error ("Can't handle as return value 0x%x", sig->ret->type);
242 #define STACKALIGN(x) (((x) + 15) & (~15))
243 #define MINFRAME ((16 + 1 + 6) * 4) /* minimum size stack frame, in bytes:
244 * 16 for registers, 1 for "hidden param",
245 * and 6 in which a callee can store it's
249 stack += MINFRAME + (local * 4);
251 fprintf (stderr, "\tstack size: %d (%d)\n\tcode size: %d\n", STACKALIGN(stack), stack, code);
254 *stack_size = STACKALIGN(stack);
259 mono_string_new_wrapper (const char *text)
261 return text ? mono_string_new (mono_domain_get (), text) : NULL;
265 mono_create_trampoline (MonoMethod *method, int runtime)
267 MonoMethodSignature *sig;
268 guint32 *p, *code_buffer;
269 guint32 local_size, stack_size, code_size;
270 guint32 arg_pos, simpletype;
271 int i, stringp, cur_out_reg;
273 sig = method->signature;
275 fprintf (stderr, "\nPInvoke [start emiting] %s\n", method->name);
276 calculate_sizes (method, &local_size, &stack_size, &code_size, runtime);
278 code_buffer = p = alloca (code_size * 4);
279 cur_out_reg = sparc_o0;
281 /* Standard function prolog. */
282 sparc_save_imm (p, sparc_sp, -stack_size, sparc_sp);
284 /* gcc seems to want to store %i0 through %i3 for some reason */
285 sparc_st_imm (p, sparc_i0, sparc_fp, 68);
286 sparc_st_imm (p, sparc_i1, sparc_fp, 72);
287 sparc_st_imm (p, sparc_i2, sparc_fp, 76);
288 sparc_st_imm (p, sparc_i3, sparc_fp, 80);
292 * We store some local vars here to handle string pointers.
293 * and align to 16 byte boundary...
297 x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size * 4);
298 stack_size = (stack_size * local_size * 4) % 16;
300 stack_size = stack_size % 16;
303 x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
307 * %i3 has the pointer to the args.
311 sparc_mov_reg_reg (p, sparc_i2, cur_out_reg);
315 /* Push arguments in reverse order. */
317 for (i = 0; i < sig->param_count; i++) {
318 arg_pos = ARG_SIZE * i;
320 if (sig->params[i]->byref) {
321 fprintf (stderr, "\tpushing params[%d] (byref): type=%s;\n", i, mono_type (sig->params[i]->type));
322 sparc_ld_imm (p, sparc_i3, arg_pos, cur_out_reg);
327 simpletype = sig->params[i]->type;
329 fprintf (stderr, "\tpushing params[%d]: type=%s;\n", i, mono_type (simpletype));
330 switch (simpletype) {
331 case MONO_TYPE_BOOLEAN:
343 case MONO_TYPE_SZARRAY:
344 case MONO_TYPE_CLASS:
345 case MONO_TYPE_OBJECT:
346 sparc_ld_imm (p, sparc_i3, arg_pos, cur_out_reg);
349 case MONO_TYPE_VALUETYPE:
350 if (sig->params[i]->data.klass->enumtype) {
351 /* it's an enum value */
352 simpletype = sig->params[i]->data.klass->enum_basetype->type;
355 /*sparc_ld_imm (p, sparc_i3, arg_pos, cur_out_reg);*/
356 sparc_ld_imm (p, sparc_i3, arg_pos, sparc_l0);
357 sparc_ld (p, sparc_l0, 0, cur_out_reg);
361 case MONO_TYPE_STRING:
362 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
363 sparc_ld_imm (p, sparc_i3, arg_pos, cur_out_reg);
369 sparc_sethi (p, mono_string_to_utf8, sparc_l0);
370 sparc_or_imm (p, 0, sparc_l0, mono_string_to_utf8, sparc_l1);
372 x86_push_membase (p, X86_EDX, arg_pos);
373 x86_mov_reg_imm (p, X86_EDX, mono_string_to_utf8);
374 x86_call_reg (p, X86_EDX);
375 x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
376 x86_push_reg (p, X86_EAX);
378 * Store the pointer in a local we'll free later.
381 x86_mov_membase_reg (p, X86_EBP, LOC_POS * stringp, X86_EAX, 4);
383 * we didn't save the reg: restore it here.
386 x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
388 fprintf (stderr, "MONO_TYPE_STRING not yet fully supported.\n");
392 sparc_ld_imm (p, sparc_i3, arg_pos, cur_out_reg);
394 sparc_ld_imm (p, sparc_i3, arg_pos + 4, cur_out_reg);
398 sparc_ld_imm (p, sparc_i3, arg_pos, cur_out_reg);
400 sparc_ld_imm (p, sparc_i3, arg_pos + 4, cur_out_reg);
404 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
408 /* call the function */
409 sparc_jmpl_imm (p, sparc_i0, 0, sparc_callsite);
414 * Small integer and pointer values are in EAX.
415 * Long integers are in EAX:EDX.
416 * FP values are on the FP stack.
419 if (sig->ret->byref) {
420 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
421 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
423 simpletype = sig->ret->type;
425 switch (simpletype) {
426 case MONO_TYPE_BOOLEAN:
429 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
430 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 1);
435 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
436 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 2);
442 case MONO_TYPE_CLASS:
443 case MONO_TYPE_OBJECT:
444 case MONO_TYPE_SZARRAY:
445 case MONO_TYPE_ARRAY:
446 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
447 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
449 case MONO_TYPE_STRING:
450 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || runtime) {
451 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
452 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
456 /* If the argument is non-null, then convert the value back */
457 x86_alu_reg_reg (p, X86_OR, X86_EAX, X86_EAX);
458 x86_branch8 (p, X86_CC_EQ, 11, FALSE);
459 x86_push_reg (p, X86_EAX);
460 x86_mov_reg_imm (p, X86_EDX, mono_string_new);
461 x86_call_reg (p, X86_EDX);
462 x86_alu_reg_imm (p, X86_ADD, X86_ESP, 4);
464 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
465 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
468 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
469 x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE);
472 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
473 x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE);
476 x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
477 x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
478 x86_mov_membase_reg (p, X86_ECX, 4, X86_EDX, 4);
480 case MONO_TYPE_VALUETYPE:
481 if (sig->ret->data.klass->enumtype) {
482 simpletype = sig->ret->data.klass->enum_basetype->type;
488 g_error ("Can't handle as return value 0x%x", sig->ret->type);
494 /* free the allocated strings... */
495 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
497 x86_mov_reg_imm (p, X86_EDX, g_free);
498 for (i = 1; i <= local_size; ++i) {
499 x86_push_membase (p, X86_EBP, LOC_POS * i);
500 x86_call_reg (p, X86_EDX);
506 * 8 may be 12 when returning structures (to skip unimp opcode).
508 sparc_jmpl_imm (p, sparc_i7, 8, sparc_zero);
509 sparc_restore (p, sparc_zero, sparc_zero, sparc_zero);
512 unsigned char *inptr, *inend;
514 inptr = (unsigned char *) code_buffer;
515 inend = (unsigned char *) p;
517 printf (".text\n.align 4\n.globl main\n.type main,function\nmain:\n");
518 while (inptr < inend) {
519 printf (".byte 0x%x\n", *inptr);
525 fprintf (stderr, "PInvoke [finish emiting] %s\n", method->name);
527 /* FIXME: need to flush */
528 return g_memdup (code_buffer, 4 * (p - code_buffer));
532 mono_create_method_pointer (MonoMethod *method)
538 mono_method_pointer_get (void *code)