You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1150 lines
36 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*------------------------------------------------------------------*/
/* */
/* Name - tramp.c */
/* */
/* Function - Create trampolines to invoke arbitrary functions. */
/* */
/* Name - Neale Ferguson. */
/* */
/* Date - October, 2002 */
/* */
/* */
/*------------------------------------------------------------------*/
/*------------------------------------------------------------------*/
/* D e f i n e s */
/*------------------------------------------------------------------*/
#define PROLOG_INS 24 /* Size of emitted prolog */
#define CALL_INS 4 /* Size of emitted call */
#define EPILOG_INS 18 /* Size of emitted epilog */
#define DEBUG(x)
/*========================= End of Defines =========================*/
/*------------------------------------------------------------------*/
/* I n c l u d e s */
/*------------------------------------------------------------------*/
#ifdef NEED_MPROTECT
# include <sys/mman.h>
# include <limits.h> /* for PAGESIZE */
# ifndef PAGESIZE
# define PAGESIZE 4096
# endif
#endif
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "s390x-codegen.h"
#include "mono/metadata/class.h"
#include "mono/metadata/tabledefs.h"
#include "mono/interpreter/interp.h"
#include "mono/metadata/appdomain.h"
#include "mono/metadata/marshal.h"
/*========================= End of Includes ========================*/
/*------------------------------------------------------------------*/
/* T y p e d e f s */
/*------------------------------------------------------------------*/
/*------------------------------------------------------------------*/
/* Structure used to accummulate size of stack, code, and locals */
/*------------------------------------------------------------------*/
typedef struct {
guint stack_size,
local_size,
code_size,
retStruct;
} size_data;
/*========================= End of Typedefs ========================*/
/*------------------------------------------------------------------*/
/* */
/* Name - add_general */
/* */
/* Function - Determine code and stack size incremements for a */
/* parameter. */
/* */
/*------------------------------------------------------------------*/
static void inline
add_general (guint *gr, size_data *sz, gboolean simple)
{
if (simple) {
if (*gr >= GENERAL_REGS) {
sz->stack_size += sizeof(long);
sz->code_size += 12;
} else {
sz->code_size += 8;
}
} else {
if (*gr >= GENERAL_REGS - 1) {
sz->stack_size += 8 + (sz->stack_size % 8);
sz->code_size += 10;
} else {
sz->code_size += 8;
}
(*gr) ++;
}
(*gr) ++;
}
/*========================= End of Function ========================*/
/*------------------------------------------------------------------*/
/* */
/* Name - calculate_sizes */
/* */
/* Function - Determine the amount of space required for code */
/* and stack. In addition determine starting points */
/* for stack-based parameters, and area for struct- */
/* ures being returned on the stack. */
/* */
/*------------------------------------------------------------------*/
static void inline
calculate_sizes (MonoMethodSignature *sig, size_data *sz,
gboolean string_ctor)
{
guint i, fr, gr, size;
guint32 simpletype, align;
fr = 0;
gr = 2;
sz->retStruct = 0;
sz->stack_size = S390_MINIMAL_STACK_SIZE;
sz->code_size = (PROLOG_INS + CALL_INS + EPILOG_INS);
sz->local_size = 0;
if (sig->hasthis) {
add_general (&gr, sz, TRUE);
}
/*----------------------------------------------------------*/
/* We determine the size of the return code/stack in case we*/
/* need to reserve a register to be used to address a stack */
/* area that the callee will use. */
/*----------------------------------------------------------*/
if (sig->ret->byref || string_ctor) {
sz->code_size += 8;
} else {
simpletype = sig->ret->type;
enum_retvalue:
switch (simpletype) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
case MONO_TYPE_U1:
case MONO_TYPE_I2:
case MONO_TYPE_U2:
case MONO_TYPE_CHAR:
case MONO_TYPE_I4:
case MONO_TYPE_U4:
case MONO_TYPE_I:
case MONO_TYPE_U:
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
case MONO_TYPE_R4:
case MONO_TYPE_R8:
case MONO_TYPE_PTR:
case MONO_TYPE_SZARRAY:
case MONO_TYPE_ARRAY:
case MONO_TYPE_STRING:
sz->code_size += 4;
break;
case MONO_TYPE_I8:
sz->code_size += 4;
break;
case MONO_TYPE_VALUETYPE:
if (sig->ret->data.klass->enumtype) {
simpletype = sig->ret->data.klass->enum_basetype->type;
goto enum_retvalue;
}
gr++;
if (sig->pinvoke)
size = mono_class_native_size (sig->ret->data.klass, &align);
else
size = mono_class_value_size (sig->ret->data.klass, &align);
if (align > 1)
sz->code_size += 10;
switch (size) {
/*----------------------------------*/
/* On S/390, structures of size 1, */
/* 2, 4, and 8 bytes are returned */
/* in (a) register(s). */
/*----------------------------------*/
case 1:
case 2:
case 4:
case 8:
sz->code_size += 16;
sz->stack_size += 4;
break;
default:
sz->retStruct = 1;
sz->code_size += 32;
}
break;
case MONO_TYPE_VOID:
break;
default:
g_error ("Can't handle as return value 0x%x", sig->ret->type);
}
}
/*----------------------------------------------------------*/
/* We determine the size of the parameter code and stack */
/* requirements by checking the types and sizes of the */
/* parameters. */
/*----------------------------------------------------------*/
for (i = 0; i < sig->param_count; ++i) {
if (sig->params [i]->byref) {
add_general (&gr, sz, TRUE);
continue;
}
simpletype = sig->params [i]->type;
enum_calc_size:
switch (simpletype) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_CHAR:
case MONO_TYPE_I1:
case MONO_TYPE_U1:
case MONO_TYPE_I2:
case MONO_TYPE_U2:
case MONO_TYPE_I4:
case MONO_TYPE_U4:
case MONO_TYPE_I:
case MONO_TYPE_U:
case MONO_TYPE_PTR:
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
case MONO_TYPE_STRING:
add_general (&gr, sz, TRUE);
break;
case MONO_TYPE_SZARRAY:
add_general (&gr, sz, TRUE);
break;
case MONO_TYPE_VALUETYPE:
if (sig->params [i]->data.klass->enumtype) {
simpletype = sig->params [i]->data.klass->enum_basetype->type;
goto enum_calc_size;
}
if (sig->pinvoke)
size = mono_class_native_size (sig->params [i]->data.klass, &align);
else
size = mono_class_value_size (sig->params [i]->data.klass, &align);
DEBUG(printf("%d typesize: %d (%d)\n",i,size,align));
switch (size) {
/*----------------------------------*/
/* On S/390, structures of size 1, */
/* 2, 4, and 8 bytes are passed in */
/* (a) register(s). */
/*----------------------------------*/
case 0:
case 1:
case 2:
case 4:
add_general(&gr, sz, TRUE);
break;
case 8:
add_general(&gr, sz, FALSE);
break;
default:
sz->local_size += (size + (size % align));
sz->code_size += 40;
}
break;
case MONO_TYPE_I8:
add_general (&gr, sz, FALSE);
break;
case MONO_TYPE_R4:
if (fr < FLOAT_REGS) {
sz->code_size += 4;
fr++;
}
else {
sz->code_size += 4;
sz->stack_size += 8;
}
break;
case MONO_TYPE_R8:
if (fr < FLOAT_REGS) {
sz->code_size += 4;
fr++;
} else {
sz->code_size += 4;
sz->stack_size += 8 + (sz->stack_size % 8);
}
break;
default:
g_error ("Can't trampoline 0x%x", sig->params [i]->type);
}
}
/* align stack size to 8 */
DEBUG (printf (" stack size: %d (%d)\n"
" code size: %d\n"
" local size: %d\n",
(sz->stack_size + 8) & ~8, sz->stack_size,
(sz->code_size),(sz->local_size + 8) & ~8));
sz->stack_size = (sz->stack_size + 8) & ~8;
sz->local_size = (sz->local_size + 8) & ~8;
}
/*========================= End of Function ========================*/
/*------------------------------------------------------------------*/
/* */
/* Name - emit_prolog */
/* */
/* Function - Create the instructions that implement the stand- */
/* ard function prolog according to the S/390 ABI. */
/* */
/*------------------------------------------------------------------*/
static inline guint8 *
emit_prolog (guint8 *p, MonoMethodSignature *sig, size_data *sz)
{
guint stack_size;
stack_size = sz->stack_size + sz->local_size;
/* function prolog */
s390_stmg(p, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
s390_lg (p, s390_r7, 0, STK_BASE, MINV_POS);
s390_lgr (p, s390_r11, STK_BASE);
s390_aghi(p, STK_BASE, -stack_size);
s390_stg (p, s390_r11, 0, STK_BASE, 0);
/*-----------------------------------------*/
/* Save: */
/* - address of "callme" */
/* - address of "retval" */
/* - address of "arguments" */
/*-----------------------------------------*/
s390_lgr (p, s390_r9, s390_r2);
s390_lgr (p, s390_r8, s390_r3);
s390_lgr (p, s390_r10, s390_r5);
return p;
}
/*========================= End of Function ========================*/
/*------------------------------------------------------------------*/
/* */
/* Name - emit_save_parameters */
/* */
/* Function - Create the instructions that load registers with */
/* parameters, place others on the stack according */
/* to the S/390 ABI. */
/* */
/* The resulting function takes the form: */
/* void func (void (*callme)(), void *retval, */
/* void *this_obj, stackval *arguments); */
/* */
/*------------------------------------------------------------------*/
inline static guint8*
emit_save_parameters (guint8 *p, MonoMethodSignature *sig, size_data *sz)
{
guint i, fr, gr, act_strs, align,
stack_par_pos, size, local_pos;
guint32 simpletype;
/*----------------------------------------------------------*/
/* If a structure on stack is being returned, reserve r2 */
/* to point to an area where it can be passed. */
/*----------------------------------------------------------*/
if (sz->retStruct)
gr = 1;
else
gr = 0;
fr = 0;
act_strs = 0;
stack_par_pos = S390_MINIMAL_STACK_SIZE;
local_pos = sz->stack_size;
if (sig->hasthis) {
s390_lr (p, s390_r2 + gr, s390_r4);
gr++;
}
act_strs = 0;
for (i = 0; i < sig->param_count; ++i) {
DEBUG(printf("par: %d type: %d ref: %d\n",i,sig->params[i]->type,sig->params[i]->byref));
if (sig->params [i]->byref) {
if (gr < GENERAL_REGS) {
s390_lg (p, s390_r2 + gr, 0, ARG_BASE, STKARG);
gr ++;
} else {
s390_lg (p, s390_r0, 0, ARG_BASE, STKARG);
s390_stg(p, s390_r0, 0, STK_BASE, stack_par_pos);
stack_par_pos += sizeof(long);
}
continue;
}
simpletype = sig->params [i]->type;
enum_calc_size:
switch (simpletype) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
case MONO_TYPE_U1:
case MONO_TYPE_I2:
case MONO_TYPE_U2:
case MONO_TYPE_CHAR:
case MONO_TYPE_I4:
case MONO_TYPE_U4:
case MONO_TYPE_I:
case MONO_TYPE_U:
case MONO_TYPE_PTR:
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
case MONO_TYPE_STRING:
case MONO_TYPE_SZARRAY:
if (gr < GENERAL_REGS) {
s390_lg (p, s390_r2 + gr, 0, ARG_BASE, STKARG);
gr ++;
} else {
s390_lg (p, s390_r0, 0, ARG_BASE, STKARG);
s390_stg(p, s390_r0, 0, STK_BASE, stack_par_pos);
stack_par_pos += sizeof(long);
}
break;
case MONO_TYPE_VALUETYPE:
if (sig->params [i]->data.klass->enumtype) {
simpletype = sig->params [i]->data.klass->enum_basetype->type;
goto enum_calc_size;
}
if (sig->pinvoke)
size = mono_class_native_size (sig->params [i]->data.klass, &align);
else
size = mono_class_value_size (sig->params [i]->data.klass, &align);
DEBUG(printf("parStruct - size %d pinvoke: %d\n",size,sig->pinvoke));
switch (size) {
case 0:
case 1:
case 2:
case 4:
if (gr < GENERAL_REGS) {
s390_lg (p, s390_r2 + gr, 0,ARG_BASE, STKARG);
s390_lgf(p, s390_r2 + gr, 0, s390_r2 + gr, 0);
gr++;
} else {
stack_par_pos += (stack_par_pos % align);
s390_lg (p, s390_r10, 0,ARG_BASE, STKARG);
s390_lgf(p, s390_r10, 0, s390_r10, 0);
s390_st (p, s390_r10, 0, STK_BASE, stack_par_pos);
stack_par_pos += sizeof(long);
}
break;
case 8:
if (gr < GENERAL_REGS) {
s390_lg (p, s390_r2 + gr, 0, ARG_BASE, STKARG);
s390_lg (p, s390_r2 + gr, 0, s390_r2 + gr, 0);
} else {
stack_par_pos += (stack_par_pos % align);
s390_lg (p, s390_r10, 0, ARG_BASE, STKARG);
s390_mvc (p, sizeof(long long), STK_BASE, stack_par_pos, s390_r10, 0);
stack_par_pos += sizeof(long long);
}
break;
default:
if (size <= 256) {
local_pos += (local_pos % align);
s390_lg (p, s390_r13, 0, ARG_BASE, STKARG);
s390_mvc (p, size, STK_BASE, local_pos, s390_r13, 0);
s390_la (p, s390_r13, 0, STK_BASE, local_pos);
local_pos += size;
} else {
local_pos += (local_pos % align);
s390_bras (p, s390_r13, 4);
s390_llong(p, size);
s390_lg (p, s390_r1, 0, s390_r13, 0);
s390_lg (p, s390_r0, 0, ARG_BASE, STKARG);
s390_lgr (p, s390_r14, s390_r12);
s390_la (p, s390_r12, 0, STK_BASE, local_pos);
s390_lgr (p, s390_r13, s390_r1);
s390_mvcl (p, s390_r12, s390_r0);
s390_lgr (p, s390_r12, s390_r14);
s390_la (p, s390_r13, 0, STK_BASE, local_pos);
local_pos += size;
}
if (gr < GENERAL_REGS) {
s390_lgr(p, s390_r2 + gr, s390_r13);
gr++;
} else {
s390_stg(p, s390_r13, 0, STK_BASE, stack_par_pos);
stack_par_pos += sizeof(long);
}
}
break;
case MONO_TYPE_I8:
if (gr < GENERAL_REGS) {
s390_lg (p, s390_r2 + gr, 0, ARG_BASE, STKARG);
gr += 2;
} else {
*(guint32 *) p += 7;
*(guint32 *) p &= ~7;
s390_mvc (p, sizeof(long long), STK_BASE, stack_par_pos, ARG_BASE, STKARG);
stack_par_pos += sizeof(long long) + (stack_par_pos % sizeof(long long));
}
break;
case MONO_TYPE_R4:
if (fr < FLOAT_REGS) {
s390_le (p, s390_r0 + fr, 0, ARG_BASE, STKARG);
fr++;
} else {
s390_mvc (p, sizeof(float), STK_BASE, stack_par_pos, ARG_BASE, STKARG);
stack_par_pos += sizeof(float);
}
break;
case MONO_TYPE_R8:
if (fr < FLOAT_REGS) {
s390_ld (p, s390_r0 + fr, 0, ARG_BASE, STKARG);
fr++;
} else {
*(guint32 *) p += 7;
*(guint32 *) p &= ~7;
s390_mvc (p, sizeof(double), STK_BASE, stack_par_pos, ARG_BASE, STKARG);
stack_par_pos += sizeof(long long) + (stack_par_pos % sizeof(long long));
}
break;
default:
g_error ("Can't trampoline 0x%x", sig->params [i]->type);
}
}
/*----------------------------------------------------------*/
/* If we're returning a structure but not in a register */
/* then point the result area for the called routine */
/*----------------------------------------------------------*/
if (sz->retStruct) {
s390_lg (p, s390_r2, 0, s390_r8, 0);
}
return p;
}
/*========================= End of Function ========================*/
/*------------------------------------------------------------------*/
/* */
/* Name - alloc_code_memory */
/* */
/* Function - Allocate space to place the emitted code. */
/* */
/*------------------------------------------------------------------*/
static inline guint8 *
alloc_code_memory (guint code_size)
{
guint8 *p;
#ifdef NEED_MPROTECT
p = g_malloc (code_size + PAGESIZE - 1);
/* Align to a multiple of PAGESIZE, assumed to be a power of two */
p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
#else
p = g_malloc (code_size);
#endif
DEBUG (printf (" align: %p (%d)\n", p, (guint)p % 4));
return p;
}
/*========================= End of Function ========================*/
/*------------------------------------------------------------------*/
/* */
/* Name - emit_call_and_store_retval */
/* */
/* Function - Emit code that will implement the call to the */
/* desired function, and unload the result according */
/* to the S390 ABI for the type of value returned */
/* */
/*------------------------------------------------------------------*/
static inline guint8 *
emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig,
size_data *sz, gboolean string_ctor)
{
guint32 simpletype;
guint retSize, align;
/* call "callme" */
s390_basr (p, s390_r14, s390_r9);
/* get return value */
if (sig->ret->byref || string_ctor) {
s390_stg(p, s390_r2, 0, s390_r8, 0);
} else {
simpletype = sig->ret->type;
enum_retvalue:
switch (simpletype) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
case MONO_TYPE_U1:
s390_stc (p, s390_r2, 0, s390_r8, 0);
break;
case MONO_TYPE_I2:
case MONO_TYPE_U2:
case MONO_TYPE_CHAR:
s390_sth (p, s390_r2, 0, s390_r8, 0);
break;
case MONO_TYPE_I4:
case MONO_TYPE_U4:
case MONO_TYPE_I:
case MONO_TYPE_U:
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
case MONO_TYPE_SZARRAY:
case MONO_TYPE_ARRAY:
case MONO_TYPE_STRING:
s390_st (p, s390_r2, 0, s390_r8, 0);
break;
case MONO_TYPE_R4:
s390_ste (p, s390_f0, 0, s390_r8, 0);
break;
case MONO_TYPE_R8:
s390_std (p, s390_f0, 0, s390_r8, 0);
break;
case MONO_TYPE_I8:
s390_stg (p, s390_r2, 0, s390_r8, 0);
break;
case MONO_TYPE_VALUETYPE:
if (sig->ret->data.klass->enumtype) {
simpletype = sig->ret->data.klass->enum_basetype->type;
goto enum_retvalue;
}
if (sig->pinvoke)
retSize = mono_class_native_size (sig->ret->data.klass, &align);
else
retSize = mono_class_value_size (sig->ret->data.klass, &align);
printf("Returning %d bytes for type %d (%d)\n",retSize,simpletype,sig->pinvoke);
switch(retSize) {
case 0:
break;
case 1:
s390_stc (p, s390_r2, 0, s390_r8, 0);
break;
case 2:
s390_sth (p, s390_r2, 0, s390_r8, 0);
break;
case 4:
s390_st (p, s390_r2, 0, s390_r8, 0);
break;
case 8:
s390_stg (p, s390_r2, 0, s390_r8, 0);
break;
default: ;
/*------------------------------------------*/
/* The callee has already placed the result */
/* in the required area */
/*------------------------------------------*/
}
break;
case MONO_TYPE_VOID:
break;
default:
g_error ("Can't handle as return value 0x%x",
sig->ret->type);
}
}
return p;
}
/*========================= End of Function ========================*/
/*------------------------------------------------------------------*/
/* */
/* Name - emit_epilog */
/* */
/* Function - Create the instructions that implement the stand- */
/* ard function epilog according to the S/390 ABI. */
/* */
/*------------------------------------------------------------------*/
static inline guint8 *
emit_epilog (guint8 *p, MonoMethodSignature *sig, size_data *sz)
{
/* function epilog */
s390_lg (p, STK_BASE, 0, STK_BASE, 0);
s390_lg (p, s390_r4, 0, STK_BASE, S390_RET_ADDR_OFFSET);
s390_lmg (p, s390_r6, STK_BASE, STK_BASE, S390_REG_SAVE_OFFSET);
s390_br (p, s390_r4);
return p;
}
/*========================= End of Function ========================*/
/*------------------------------------------------------------------*/
/* */
/* Name - mono_arch_create_trampoline. */
/* */
/* Function - Create the code that will allow a mono method to */
/* invoke a system subroutine. */
/* */
/*------------------------------------------------------------------*/
MonoPIFunc
mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
{
guint8 *p, *code_buffer;
size_data sz;
DEBUG (printf ("\nPInvoke [start emiting]\n"));
calculate_sizes (sig, &sz, string_ctor);
p = code_buffer = alloc_code_memory (sz.code_size);
p = emit_prolog (p, sig, &sz);
p = emit_save_parameters (p, sig, &sz);
p = emit_call_and_store_retval (p, sig, &sz, string_ctor);
p = emit_epilog (p, sig, &sz);
#ifdef NEED_MPROTECT
if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
g_error ("Cannot mprotect trampoline\n");
}
#endif
DEBUG (printf ("emited code size: %d\n", p - code_buffer));
DEBUG (printf ("PInvoke [end emiting]\n"));
return (MonoPIFunc) code_buffer;
}
/*========================= End of Function ========================*/
/*------------------------------------------------------------------*/
/* */
/* Name - mono_arch_create_method_pointer */
/* */
/* Function - Returns a pointer to a native function that can */
/* be used to call the specified method. */
/* */
/* The function created will receive the arguments */
/* according to the calling convention specified in */
/* in the method. */
/* */
/* This function works by creating a MonoInvocation */
/* structure, filling the fields in and calling */
/* ves_exec_method() on it. */
/* */
/* Logic: */
/* ------ */
/* mono_arch_create_method_pointer (MonoMethod *method) */
/* create the unmanaged->managed wrapper */
/* register it with mono_jit_info_table_add() */
/* */
/* What does the unmanaged->managed wrapper do? */
/* allocate a MonoInvocation structure (inv) on the stack */
/* allocate an array of stackval on the stack with length = */
/* method->signature->param_count + 1 [call it stack_args] */
/* set inv->ex, inv->ex_handler, inv->parent to NULL */
/* set inv->method to method */
/* if method is an instance method, set inv->obj to the */
/* 'this' argument (the first argument) else set to NULL */
/* for each argument to the method call: */
/* stackval_from_data (sig->params[i], &stack_args[i], */
/* arg, sig->pinvoke); */
/* Where: */
/* ------ */
/* sig - is method->signature */
/* &stack_args[i] - is the pointer to the ith element */
/* in the stackval array */
/* arg - is a pointer to the argument re- */
/* ceived by the function according */
/* to the call convention. If it */
/* gets passed in a register, save */
/* on the stack first. */
/* */
/* set inv->retval to the address of the last element of */
/* stack_args [recall we allocated param_count+1 of them] */
/* call ves_exec_method(inv) */
/* copy the returned value from inv->retval where the calling */
/* convention expects to find it on return from the wrap- */
/* per [if it's a structure, use stackval_to_data] */
/* */
/*------------------------------------------------------------------*/
void *
mono_arch_create_method_pointer (MonoMethod *method)
{
MonoMethodSignature *sig;
MonoJitInfo *ji;
guint8 *p, *code_buffer;
guint i, align = 0, simple_type, retSize, reg_save = 0,
stackval_arg_pos, local_pos, float_pos,
local_start, reg_param = 0, stack_param,
this_flag, arg_pos, fpr_param, parSize;
guint32 simpletype;
size_data sz;
int *vtbuf, cpos, vt_cur;
sz.code_size = 1024;
sz.stack_size = 1024;
stack_param = 0;
fpr_param = 0;
arg_pos = 0;
sig = method->signature;
p = code_buffer = g_malloc (sz.code_size);
DEBUG (printf ("\nDelegate [start emiting] %s at 0x%08x\n",
method->name,p));
/*----------------------------------------------------------*/
/* prolog */
/*----------------------------------------------------------*/
s390_stmg(p, s390_r6, STK_BASE, STK_BASE, S390_REG_SAVE_OFFSET);
s390_lg (p, s390_r7, 0, STK_BASE, MINV_POS);
s390_lgr (p, s390_r0, STK_BASE);
s390_aghi(p, STK_BASE, -(sz.stack_size+MINV_POS));
s390_stg (p, s390_r0, 0, STK_BASE, 0);
s390_la (p, s390_r8, 0, STK_BASE, 4);
s390_lgr (p, s390_r10, s390_r8);
s390_lghi(p, s390_r9, sz.stack_size+92);
s390_lghi(p, s390_r11, 0);
s390_mvcl(p, s390_r8, s390_r10);
/*----------------------------------------------------------*/
/* Let's fill MonoInvocation - first zero some fields */
/*----------------------------------------------------------*/
s390_lghi (p, s390_r0, 0);
s390_stg (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)));
s390_stg (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)));
s390_stg (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)));
s390_lghi (p, s390_r0, 1);
s390_stg (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, invoke_trap)));
/*----------------------------------------------------------*/
/* set method pointer */
/*----------------------------------------------------------*/
s390_bras (p, s390_r13, 4);
s390_llong(p, method);
s390_lg (p, s390_r0, 0, s390_r13, 0);
s390_stg (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)));
local_start = local_pos = MINV_POS +
sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval);
this_flag = (sig->hasthis ? 1 : 0);
/*----------------------------------------------------------*/
/* if we are returning a structure, checks it's length to */
/* see if there's a "hidden" parameter that points to the */
/* area. If necessary save this hidden parameter for later */
/*----------------------------------------------------------*/
if (MONO_TYPE_ISSTRUCT(sig->ret)) {
if (sig->pinvoke)
retSize = mono_class_native_size (sig->ret->data.klass, &align);
else
retSize = mono_class_value_size (sig->ret->data.klass, &align);
switch(retSize) {
case 0:
case 1:
case 2:
case 4:
case 8:
sz.retStruct = 0;
break;
default:
sz.retStruct = 1;
s390_lgr(p, s390_r8, s390_r2);
reg_save = 1;
}
} else {
reg_save = 0;
}
if (this_flag) {
s390_stg (p, s390_r2 + reg_save, 0, STK_BASE,
(MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)));
reg_param++;
} else {
s390_stg (p, s390_r2 + reg_save, 0, STK_BASE, local_pos);
local_pos += sizeof(int);
s390_stg (p, s390_r0, 0, STK_BASE,
(MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)));
}
s390_stmg (p, s390_r3 + reg_param, s390_r6, STK_BASE, local_pos);
local_pos += 4 * sizeof(long);
float_pos = local_pos;
s390_std (p, s390_f0, 0, STK_BASE, local_pos);
local_pos += sizeof(double);
s390_std (p, s390_f2, 0, STK_BASE, local_pos);
local_pos += sizeof(double);
/*----------------------------------------------------------*/
/* prepare space for valuetypes */
/*----------------------------------------------------------*/
vt_cur = local_pos;
vtbuf = alloca (sizeof(int)*sig->param_count);
cpos = 0;
for (i = 0; i < sig->param_count; i++) {
MonoType *type = sig->params [i];
vtbuf [i] = -1;
DEBUG(printf("par: %d type: %d ref: %d\n",i,type->type,type->byref));
if (type->type == MONO_TYPE_VALUETYPE) {
MonoClass *klass = type->data.klass;
gint size;
if (klass->enumtype)
continue;
size = mono_class_native_size (klass, &align);
cpos += align - 1;
cpos &= ~(align - 1);
vtbuf [i] = cpos;
cpos += size;
}
}
cpos += 3;
cpos &= ~3;
local_pos += cpos;
/*----------------------------------------------------------*/
/* set MonoInvocation::stack_args */
/*----------------------------------------------------------*/
stackval_arg_pos = MINV_POS + sizeof (MonoInvocation);
s390_la (p, s390_r0, 0, STK_BASE, stackval_arg_pos);
s390_stg (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)));
/*----------------------------------------------------------*/
/* add stackval arguments */
/*----------------------------------------------------------*/
for (i = 0; i < sig->param_count; ++i) {
if (sig->params [i]->byref) {
ADD_ISTACK_PARM(0, 1);
} else {
simple_type = sig->params [i]->type;
enum_savechk:
switch (simple_type) {
case MONO_TYPE_I8:
ADD_ISTACK_PARM(-1, 2);
break;
case MONO_TYPE_R4:
ADD_RSTACK_PARM(1);
break;
case MONO_TYPE_R8:
ADD_RSTACK_PARM(2);
break;
case MONO_TYPE_VALUETYPE:
if (sig->params [i]->data.klass->enumtype) {
simple_type = sig->params [i]->data.klass->enum_basetype->type;
goto enum_savechk;
}
if (sig->pinvoke)
parSize = mono_class_native_size (sig->params [i]->data.klass, &align);
else
parSize = mono_class_value_size (sig->params [i]->data.klass, &align);
switch(parSize) {
case 0:
case 1:
case 2:
case 4:
ADD_PSTACK_PARM(0, 1);
break;
case 8:
ADD_PSTACK_PARM(-1, 2);
break;
default:
ADD_TSTACK_PARM;
}
break;
default:
ADD_ISTACK_PARM(0, 1);
}
}
if (vtbuf [i] >= 0) {
s390_la (p, s390_r3, 0, STK_BASE, vt_cur);
s390_stg (p, s390_r3, 0, STK_BASE, stackval_arg_pos);
s390_la (p, s390_r3, 0, STK_BASE, stackval_arg_pos);
vt_cur += vtbuf [i];
} else {
s390_la (p, s390_r3, 0, STK_BASE, stackval_arg_pos);
}
/*--------------------------------------*/
/* Load the parameter registers for the */
/* call to stackval_from_data */
/*--------------------------------------*/
s390_bras (p, s390_r13, 8);
s390_llong(p, sig->params [i]);
s390_llong(p, sig->pinvoke);
s390_llong(p, stackval_from_data);
s390_lg (p, s390_r2, 0, s390_r13, 0);
s390_lg (p, s390_r5, 0, s390_r13, 4);
s390_lg (p, s390_r1, 0, s390_r13, 8);
s390_basr (p, s390_r14, s390_r1);
stackval_arg_pos += sizeof(stackval);
/* fixme: alignment */
DEBUG (printf ("arg_pos %d --> ", arg_pos));
if (sig->pinvoke)
arg_pos += mono_type_native_stack_size (sig->params [i], &align);
else
arg_pos += mono_type_stack_size (sig->params [i], &align);
DEBUG (printf ("%d\n", stackval_arg_pos));
}
/*----------------------------------------------------------*/
/* Set return area pointer. */
/*----------------------------------------------------------*/
s390_la (p, s390_r10, 0, STK_BASE, stackval_arg_pos);
s390_stg(p, s390_r10, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)));
if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
MonoClass *klass = sig->ret->data.klass;
if (!klass->enumtype) {
s390_la (p, s390_r9, 0, s390_r10, sizeof(stackval));
s390_st (p, s390_r9, 0,STK_BASE, stackval_arg_pos);
stackval_arg_pos += sizeof(stackval);
}
}
/*----------------------------------------------------------*/
/* call ves_exec_method */
/*----------------------------------------------------------*/
s390_bras (p, s390_r13, 4);
s390_llong(p, ves_exec_method);
s390_lg (p, s390_r1, 0, s390_r13, 0);
s390_la (p, s390_r2, 0, STK_BASE, MINV_POS);
s390_basr (p, s390_r14, s390_r1);
/*----------------------------------------------------------*/
/* move retval from stackval to proper place (r3/r4/...) */
/*----------------------------------------------------------*/
DEBUG(printf("retType: %d byRef: %d\n",sig->ret->type,sig->ret->byref));
if (sig->ret->byref) {
DEBUG (printf ("ret by ref\n"));
s390_stg(p, s390_r2, 0, s390_r10, 0);
} else {
enum_retvalue:
switch (sig->ret->type) {
case MONO_TYPE_VOID:
break;
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_U1:
s390_lghi(p, s390_r2, 0);
s390_ic (p, s390_r2, 0, s390_r10, 0);
break;
case MONO_TYPE_I2:
case MONO_TYPE_U2:
s390_lh (p, s390_r2, 0,s390_r10, 0);
break;
case MONO_TYPE_I4:
case MONO_TYPE_U4:
case MONO_TYPE_I:
case MONO_TYPE_U:
s390_lgf(p, s390_r2, 0, s390_r10, 0);
break;
case MONO_TYPE_OBJECT:
case MONO_TYPE_STRING:
case MONO_TYPE_CLASS:
case MONO_TYPE_I8:
s390_lg (p, s390_r2, 0, s390_r10, 0);
break;
case MONO_TYPE_R4:
s390_le (p, s390_f0, 0, s390_r10, 0);
break;
case MONO_TYPE_R8:
s390_ld (p, s390_f0, 0, s390_r10, 0);
break;
case MONO_TYPE_VALUETYPE:
if (sig->ret->data.klass->enumtype) {
simpletype = sig->ret->data.klass->enum_basetype->type;
goto enum_retvalue;
}
/*---------------------------------*/
/* Call stackval_to_data to return */
/* the structure */
/*---------------------------------*/
s390_bras (p, s390_r13, 8);
s390_llong(p, sig->ret);
s390_llong(p, sig->pinvoke);
s390_llong(p, stackval_to_data);
s390_lg (p, s390_r2, 0, s390_r13, 0);
s390_lg (p, s390_r3, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)));
if (sz.retStruct) {
/*------------------------------------------*/
/* Get stackval_to_data to set result area */
/*------------------------------------------*/
s390_lgr (p, s390_r4, s390_r8);
} else {
/*------------------------------------------*/
/* Give stackval_to_data a temp result area */
/*------------------------------------------*/
s390_la (p, s390_r4, 0, STK_BASE, stackval_arg_pos);
}
s390_lg (p, s390_r5, 0,s390_r13, 4);
s390_lg (p, s390_r1, 0, s390_r13, 8);
s390_basr (p, s390_r14, s390_r1);
switch (retSize) {
case 0:
break;
case 1:
s390_lghi(p, s390_r2, 0);
s390_ic (p, s390_r2, 0, s390_r10, 0);
break;
case 2:
s390_lh (p, s390_r2, 0, s390_r10, 0);
break;
case 4:
s390_lgf(p, s390_r2, 0, s390_r10, 0);
break;
case 8:
s390_lg (p, s390_r2, 0, s390_r10, 0);
break;
default: ;
/*-------------------------------------------------*/
/* stackval_to_data has placed data in result area */
/*-------------------------------------------------*/
}
break;
default:
g_error ("Type 0x%x not handled yet in thunk creation",
sig->ret->type);
break;
}
}
/*----------------------------------------------------------*/
/* epilog */
/*----------------------------------------------------------*/
s390_lg (p, STK_BASE, 0, STK_BASE, 0);
s390_lg (p, s390_r4, 0, STK_BASE, S390_RET_ADDR_OFFSET);
s390_lmg (p, s390_r6, STK_BASE, STK_BASE, S390_REG_SAVE_OFFSET);
s390_br (p, s390_r4);
DEBUG (printf ("emited code size: %d\n", p - code_buffer));
DEBUG (printf ("Delegate [end emiting]\n"));
ji = g_new0 (MonoJitInfo, 1);
ji->method = method;
ji->code_size = p - code_buffer;
ji->code_start = code_buffer;
mono_jit_info_table_add (mono_get_root_domain (), ji);
return ji->code_start;
}
/*========================= End of Function ========================*/