#include <mono/metadata/mono-endian.h>
#include <mono/metadata/tokentype.h>
#include <mono/arch/x86/x86-codegen.h>
+#include <mono/io-layer/io-layer.h>
#include "jit.h"
#include "regset.h"
MonoJitInfoTable *mono_jit_info_table = NULL;
+/* last managed frame (used by pinvoke) */
+guint32 lmf_thread_id = 0;
+
/*
* We sometimes need static data, for example the forest generator need it to
* store constants or class data.
* Disassemble to code to stdout.
*/
void
-mono_disassemble_code (guint8 *code, int size)
+mono_disassemble_code (guint8 *code, int size, char *id)
{
int i;
FILE *ofd;
if (!(ofd = fopen ("/tmp/test.s", "w")))
g_assert_not_reached ();
+ fprintf (ofd, "%s:\n", id);
+
for (i = 0; i < size; ++i)
fprintf (ofd, ".byte %d\n", (unsigned int) code [i]);
t = mono_ctree_new (mp, stind, addr, s);
- if (!type->byref && type->type == MONO_TYPE_VALUETYPE)
+ if (ISSTRUCT (type))
t->data.i = mono_class_value_size (type->data.klass, NULL);
return t;
case CEE_CEQ:
case CEE_CLT:
+ case CEE_CGT:
ip++;
break;
case CEE_LDARG:
}
}
- if (signature->ret->type == MONO_TYPE_VALUETYPE) {
+ if (ISSTRUCT (signature->ret)) {
int size, align;
- // fixme: maybe we must add this check to the above if statement
- g_assert (!signature->ret->byref);
-
cfg->has_vtarg = 1;
size = mono_type_size (signature->ret, &align);
ci = mono_mempool_alloc0 (mp, sizeof (MethodCallInfo));
ci->m = cm;
- if ((cm->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
- !(cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
- pinvoke = TRUE;
+ if (cm->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
+ if (!(cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
+ pinvoke = TRUE;
+
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_SAVE_LMF);
+ t1->data.m = cm;
+ ADD_TREE (t1, cli_addr);
+ }
if ((cm->flags & METHOD_ATTRIBUTE_FINAL) ||
!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
g_assert (csig->call_convention == MONO_CALL_DEFAULT);
g_assert (!virtual || csig->hasthis);
- /* fixme: we need to unbox the this pointer for value types */
+ /* fixme: we need to unbox the this pointer for value types ?*/
g_assert (!virtual || !cm->klass->valuetype);
nargs = csig->param_count;
} else
this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
- if (csig->ret->type == MONO_TYPE_VALUETYPE) {
+ if (ISSTRUCT (csig->ret)) {
int size, align;
size = mono_type_size (csig->ret, &align);
vtype_num = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
}
+ if (cm->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_RESTORE_LMF);
+ ADD_TREE (t1, cli_addr);
+ }
+
break;
}
case CEE_ISINST: {
if (ret->type != MONO_TYPE_VOID) {
--sp;
- if (!ret->byref && ret->type == MONO_TYPE_VALUETYPE) {
+ if (ISSTRUCT (ret)) {
int align;
t1 = mono_ctree_new (mp, MB_TERM_RET_OBJ, *sp, NULL);
t1->data.i = mono_class_value_size (ret->data.klass, &align);
MAKE_CMP (CEQ)
MAKE_CMP (CLT)
+ MAKE_CMP (CGT)
case CEE_RETHROW: {
++ip;
mono_jit_info_table = mono_jit_info_table_new ();
+ lmf_thread_id = TlsAlloc ();
+ TlsSetValue (lmf_thread_id, NULL);
+
mono_install_runtime_class_init (runtime_class_init);
mono_install_runtime_object_init (runtime_object_init);
+ mono_install_handler (arch_get_throw_exception ());
mono_init ();
/*
guint64 mono_lldiv_un (guint64 a, guint64 b);
guint64 mono_llrem_un (guint64 a, guint64 b);
-gpointer
-get_throw_exception (void);
+gpointer arch_get_lmf_addr (void);
gpointer
get_mono_object_isinst (void);
#define EMIT_COND_EXCEPTION(cond, exc) \
do { \
x86_branch8 (s->code, cond, 12, TRUE); \
- x86_mov_reg_imm (s->code, X86_ECX, exc); \
- x86_mov_reg_imm (s->code, X86_EAX, get_throw_exception ()); \
+ x86_push_imm (s->code, exc); \
+ x86_mov_reg_imm (s->code, X86_EAX, arch_get_throw_exception ()); \
x86_call_reg (s->code, X86_EAX); \
} while (0);
%term BREAK SWITCH BR RET_VOID RET RET_OBJ ENDFINALLY
%term ADD SUB MUL DIV DIV_UN REM REM_UN AND OR XOR SHL SHR SHR_UN NEG NOT
%term BLT BLT_UN BEQ BNE_UN BRTRUE BRFALSE BGE BGE_UN BLE BLE_UN BGT BGT_UN
-%term CEQ CLT
+%term CEQ CLT CGT
%term CONV_I4 CONV_I1 CONV_I2 CONV_I8 CONV_U8 CONV_R4 CONV_R8
%term INTF_ADDR VFUNC_ADDR NOP NEWARR NEWOBJ NEWSTRUCT CPOBJ POP INITOBJ
%term ISINST CASTCLASS UNBOX
%term CONV_OVF_I1 CONV_OVF_U1 CONV_OVF_I2 CONV_OVF_U2 CONV_OVF_U4 CONV_OVF_U8 CONV_OVF_I4
%term CONV_OVF_I2_UN CONV_OVF_I8_UN CONV_OVF_I1_UN
-%term EXCEPTION THROW RETHROW HANDLER
+%term EXCEPTION THROW RETHROW HANDLER SAVE_LMF RESTORE_LMF
%term LDLEN
#
stmt: THROW (reg) {
tree->is_jump = TRUE;
- if (tree->left->reg1 != X86_ECX)
- x86_mov_reg_reg (s->code, X86_ECX, tree->left->reg1, 4);
-
- x86_call_code (s->code, get_throw_exception ());
+ x86_push_reg (s->code, tree->left->reg1);
+ x86_call_code (s->code, arch_get_throw_exception ());
}
stmt: RETHROW {
tree->is_jump = TRUE;
- x86_mov_reg_membase (s->code, X86_ECX, X86_EBP, offset, 4);
-
- x86_call_code (s->code, get_throw_exception ());
+ x86_push_membase (s->code, X86_EBP, offset);
+ x86_call_code (s->code, arch_get_throw_exception ());
}
stmt: HANDLER {
x86_ret (s->code);
}
+stmt: SAVE_LMF {
+ tree->is_jump = TRUE;
+
+
+ /* save all caller saved regs */
+ x86_push_reg (s->code, X86_EBX);
+ x86_push_reg (s->code, X86_EDI);
+ x86_push_reg (s->code, X86_ESI);
+ x86_push_reg (s->code, X86_EBP);
+
+ /* save the IP */
+ x86_push_imm (s->code, s->code);
+
+ /* save method info */
+ x86_push_imm (s->code, tree->data.m);
+ /* get the address of lmf for the current thread */
+ x86_call_code (s->code, arch_get_lmf_addr);
+ /* push lmf */
+ x86_push_reg (s->code, X86_EAX);
+ /* push *lfm (previous_lmf) */
+ x86_push_membase (s->code, X86_EAX, 0);
+ /* *(lmf) = ESP */
+ x86_mov_membase_reg (s->code, X86_EAX, 0, X86_ESP, 4);
+}
+
+stmt: RESTORE_LMF {
+ /* ebx = previous_lmf */
+ x86_pop_reg (s->code, X86_EBX);
+ /* edi = lmf */
+ x86_pop_reg (s->code, X86_EDI);
+ /* *(lmf) = previous_lmf */
+ x86_mov_membase_reg (s->code, X86_EDI, 0, X86_EBX, 4);
+
+ /* discard method info */
+ x86_pop_reg (s->code, X86_ESI);
+
+ /* discard save IP */
+ x86_pop_reg (s->code, X86_ESI);
+
+ /* restore caller saved regs */
+ x86_pop_reg (s->code, X86_EBP);
+ x86_pop_reg (s->code, X86_ESI);
+ x86_pop_reg (s->code, X86_EDI);
+ x86_pop_reg (s->code, X86_EBX);
+}
+
stmt: STIND_I4 (addr, reg) {
PRINT_REG ("STIND_I4", tree->right->reg1);
x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
}
+reg: CGT (reg, reg) {
+ x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
+ x86_set_reg (s->code, X86_CC_GT, tree->reg1, TRUE);
+ x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
+}
+
reg: CLT (reg, reg) {
x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
x86_set_reg (s->code, X86_CC_LT, tree->reg1, TRUE);
}
}
+
+stmt: ARG_I4 (LDIND_I4 (addr)) {
+ MBTree *at = tree->left->left;
+
+ switch (at->data.ainfo.amode) {
+
+ case AMImmediate:
+ x86_push_mem (s->code, at->data.ainfo.offset);
+ break;
+
+ case AMBase:
+ x86_push_membase (s->code, at->data.ainfo.basereg, at->data.ainfo.offset);
+ break;
+ case AMIndex:
+ x86_push_memindex (s->code, X86_NOBASEREG, at->data.ainfo.offset,
+ at->data.ainfo.indexreg, at->data.ainfo.shift);
+ break;
+ case AMBaseIndex:
+ x86_push_memindex (s->code, at->data.ainfo.basereg,
+ at->data.ainfo.offset, at->data.ainfo.indexreg,
+ at->data.ainfo.shift);
+ break;
+ }
+}
+
+stmt: ARG_I4 (LDIND_U4 (addr)) {
+ MBTree *at = tree->left->left;
+
+ switch (at->data.ainfo.amode) {
+
+ case AMImmediate:
+ x86_push_mem (s->code, at->data.ainfo.offset);
+ break;
+
+ case AMBase:
+ x86_push_membase (s->code, at->data.ainfo.basereg, at->data.ainfo.offset);
+ break;
+ case AMIndex:
+ x86_push_memindex (s->code, X86_NOBASEREG, at->data.ainfo.offset,
+ at->data.ainfo.indexreg, at->data.ainfo.shift);
+ break;
+ case AMBaseIndex:
+ x86_push_memindex (s->code, at->data.ainfo.basereg,
+ at->data.ainfo.offset, at->data.ainfo.indexreg,
+ at->data.ainfo.shift);
+ break;
+ }
+}
+
stmt: ARG_I4 (reg) {
x86_push_reg (s->code, tree->left->reg1);
PRINT_REG ("ARG_I4", tree->left->reg1);
if (lreg == treg || rreg == treg)
g_assert_not_reached ();
+ if (tree->left->op != MB_TERM_NOP) {
+ g_assert (lreg >= 0);
+ x86_push_reg (s->code, lreg);
+ }
+
if (ci->vtype_num) {
int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
- if (tree->left->op != MB_TERM_NOP) {
- g_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
x86_call_reg (s->code, rreg);
if (ci->args_size)
if (lreg == treg)
treg = X86_EDX;
+ if (tree->left->op != MB_TERM_NOP) {
+ g_assert (lreg >= 0);
+ x86_push_reg (s->code, lreg);
+ }
+
if (ci->vtype_num) {
int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
- if (tree->left->op != MB_TERM_NOP) {
- g_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
x86_call_mem (s->code, tree->right->left->data.p);
if (ci->args_size)
if (lreg == treg)
treg = X86_EDX;
+ if (tree->left->op != MB_TERM_NOP) {
+ g_assert (lreg >= 0);
+ x86_push_reg (s->code, lreg);
+ }
+
if (ci->vtype_num) {
int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
- if (tree->left->op != MB_TERM_NOP) {
- g_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_mov_reg_membase (s->code, lreg, lreg,
G_STRUCT_OFFSET (MonoClass, interface_offsets), 4);
if (lreg == treg)
treg = X86_EDX;
+ if (tree->left->op != MB_TERM_NOP) {
+ g_assert (lreg >= 0);
+ x86_push_reg (s->code, lreg);
+ }
+
if (ci->vtype_num) {
int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
- if (tree->left->op != MB_TERM_NOP) {
- g_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_call_virtual (s->code, lreg,
G_STRUCT_OFFSET (MonoClass, vtable) + (tree->right->data.m->slot << 2));
x86_push_reg (s->code, treg);
}
-
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_mov_reg_membase (s->code, lreg, lreg,
G_STRUCT_OFFSET (MonoClass, interface_offsets), 4);
x86_branch8 (s->code, X86_CC_EQ, 17, TRUE);
/* throw exception */
- x86_mov_reg_imm (s->code, X86_ECX, get_exception_overflow ());
- x86_mov_reg_imm (s->code, X86_EAX, get_throw_exception ());
+ x86_push_imm (s->code, get_exception_overflow ());
+ x86_mov_reg_imm (s->code, X86_EAX, arch_get_throw_exception ());
x86_call_reg (s->code, X86_EAX);
/* our top bit is set, check that top word is 0xfffffff */
lreg: CONV_OVF_U8 (CONST_I4) {
if (tree->left->data.i < 0){
- x86_mov_reg_imm (s->code, X86_ECX, get_exception_overflow ());
- x86_mov_reg_imm (s->code, X86_EAX, get_throw_exception ());
+ x86_push_imm (s->code, get_exception_overflow ());
+ x86_mov_reg_imm (s->code, X86_EAX, arch_get_throw_exception ());
x86_call_reg (s->code, X86_EAX);
} else {
x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
if (lreg == treg)
treg = X86_EDX;
+ if (tree->left->op != MB_TERM_NOP) {
+ g_assert (lreg >= 0);
+ x86_push_reg (s->code, lreg);
+ }
+
if (ci->vtype_num) {
int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
+ x86_call_mem (s->code, tree->right->left->data.p);
+
+ if (ci->args_size)
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
+
+ g_assert (tree->reg1 == X86_EAX);
+ g_assert (tree->reg2 == X86_EDX);
+}
+
+lreg: CALL_I8 (this, VFUNC_ADDR) {
+ MethodCallInfo *ci = tree->data.ci;
+ int lreg = tree->left->reg1;
+ int treg = X86_EAX;
+
+ if (lreg == treg)
+ treg = X86_EDX;
+
if (tree->left->op != MB_TERM_NOP) {
g_assert (lreg >= 0);
x86_push_reg (s->code, lreg);
}
- x86_call_mem (s->code, tree->right->left->data.p);
+ if (ci->vtype_num) {
+ int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
+ x86_lea_membase (s->code, treg, X86_EBP, offset);
+ x86_push_reg (s->code, treg);
+ }
+
+ x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
+ x86_call_virtual (s->code, lreg,
+ G_STRUCT_OFFSET (MonoClass, vtable) + (tree->right->data.m->slot << 2));
if (ci->args_size)
x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
+ PRINT_REG ("CALL0_I8(VIRTUAL)", tree->reg1);
+ PRINT_REG ("CALL1_I8(VIRTUAL)", tree->reg2);
+
g_assert (tree->reg1 == X86_EAX);
g_assert (tree->reg2 == X86_EDX);
}
if (lreg == treg)
treg = X86_EDX;
+ if (tree->left->op != MB_TERM_NOP) {
+ g_assert (lreg >= 0);
+ x86_push_reg (s->code, lreg);
+ }
+
if (ci->vtype_num) {
int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
- if (tree->left->op != MB_TERM_NOP) {
- g_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
x86_call_mem (s->code, tree->right->left->data.p);
if (ci->args_size)
if (lreg == treg)
treg = X86_EDX;
+ if (tree->left->op != MB_TERM_NOP) {
+ g_assert (lreg >= 0);
+ x86_push_reg (s->code, lreg);
+ }
+
if (ci->vtype_num) {
int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
- if (tree->left->op != MB_TERM_NOP) {
- g_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_mov_reg_membase (s->code, lreg, lreg,
G_STRUCT_OFFSET (MonoClass, interface_offsets), 4);
if (lreg == treg)
treg = X86_EDX;
+ if (tree->left->op != MB_TERM_NOP) {
+ g_assert (lreg >= 0);
+ x86_push_reg (s->code, lreg);
+ }
+
if (ci->vtype_num) {
int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
- if (tree->left->op != MB_TERM_NOP) {
- g_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_call_virtual (s->code, lreg,
G_STRUCT_OFFSET (MonoClass, vtable) + (tree->right->data.m->slot << 2));
return mono_ctree_new (mp, op, NULL, NULL);
}
-static void
-throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
- unsigned long esi, unsigned long edi, unsigned long ebp, unsigned long eip,
- unsigned long esp)
-{
- MonoObject *exc = (gpointer)ecx;
- struct sigcontext ctx;
-
- ctx.esp = esp;
- ctx.eip = eip;
- ctx.ebp = ebp;
- ctx.edi = edi;
- ctx.esi = esi;
- ctx.ebx = ebx;
- ctx.edx = edx;
- ctx.ecx = ecx;
- ctx.eax = eax;
-
- arch_handle_exception (&ctx, exc);
-
- g_assert_not_reached ();
-}
-
gpointer
-get_throw_exception (void)
+arch_get_lmf_addr (void)
{
- static guint8 *start = NULL;
- guint8 *code;
+ gpointer *lmf;
- if (start)
- return start;
+ if ((lmf = TlsGetValue (lmf_thread_id)))
+ return lmf;
- code = start = g_malloc (1024);
+ lmf = g_malloc (sizeof (gpointer));
+ *lmf = NULL;
- x86_push_reg (code, X86_ESP);
- x86_push_membase (code, X86_ESP, 4); /* IP */
- x86_push_reg (code, X86_EBP);
- x86_push_reg (code, X86_EDI);
- x86_push_reg (code, X86_ESI);
- x86_push_reg (code, X86_EBX);
- x86_push_reg (code, X86_EDX);
- x86_push_reg (code, X86_ECX);
- x86_push_reg (code, X86_EAX);
- x86_call_code (code, throw_exception);
- /* we should never reach this breakpoint */
- x86_breakpoint (code);
+ TlsSetValue (lmf_thread_id, lmf);
- return start;
+ return lmf;
}
+
#ifdef DEBUG
void *
MEMCOPY (void *dest, const void *src, size_t n)