* jit.c (mono_allocate_intvar): bug fix.
* emit-x86.c (get_unbox_trampoline): impl.
* jit.c (mono_analyze_stack): impl STOBJ, LEAVE
* x86.brg: raise more exceptions.
svn path=/trunk/mono/; revision=1539
+2001-12-07 Dietmar Maurer <dietmar@ximian.com>
+
+ * jit.c (mono_allocate_intvar): bug fix.
+
+ * emit-x86.c (get_unbox_trampoline): impl.
+
+ * jit.c (mono_analyze_stack): impl STOBJ, LEAVE
+
+2001-12-06 Dietmar Maurer <dietmar@ximian.com>
+
+ * x86.brg: raise exceptions.
+
+2001-12-05 Dietmar Maurer <dietmar@ximian.com>
+
+ * x86.brg: impl. CEQ for freg, NEWSTRUCT now allocates valuetypes on
+ the stack.
+
2001-12-06 Miguel de Icaza <miguel@ximian.com>
* jit.c (mono_analyze_stack), x86.brg: Implement CONV.OVF.I1,
Implement CONV_OVF_XXX (constant) variants that emit either
loads or exceptions (as we can always tell)
-
\ No newline at end of file
+
+* thread does not work with the jit (mcs/tests/test-19.cs)??
\ No newline at end of file
MonoClass *class;
MonoObject *o;
- printf ("ENTER: %s.%s::%s (", method->klass->name_space,
+ printf ("ENTER: %s.%s::%s\n(", method->klass->name_space,
method->klass->name, method->name);
ebp += 8;
printf ("value:%p, ", *((gpointer *)ebp));
} else {
o = *((MonoObject **)ebp);
+
+ g_assert (o);
+
class = o->klass;
if (class == mono_defaults.string_class) {
- printf ("this:%p[STRING:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
-
+ printf ("this:[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
} else {
printf ("this:%p[%s.%s], ", o, class->name_space, class->name);
}
case MONO_TYPE_U:
printf ("%d, ", *((int *)(ebp)));
break;
- case MONO_TYPE_STRING:
- printf ("[STRING:%s], ", mono_string_to_utf8 (*(MonoString **)(ebp)));
+ case MONO_TYPE_STRING: {
+ MonoString *s = *((MonoString **)ebp);
+ if (s) {
+ g_assert (((MonoObject *)s)->klass == mono_defaults.string_class);
+ printf ("[STRING:%p:%s], ", s, mono_string_to_utf8 (s));
+ } else
+ printf ("[STRING:null], ");
break;
- case MONO_TYPE_PTR:
+ }
case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
+ case MONO_TYPE_OBJECT: {
+ o = *((MonoObject **)ebp);
+ if (o) {
+ class = o->klass;
+ if (class == mono_defaults.string_class) {
+ printf ("[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
+ } else if (class == mono_defaults.int32_class) {
+ printf ("[INT32:%p:%d], ", o, *(gint32 *)((gpointer)o + sizeof (MonoObject)));
+ } else
+ printf ("[%s.%s:%p], ", class->name_space, class->name, o);
+ } else {
+ printf ("%p, ", *((gpointer *)(ebp)));
+ }
+ break;
+ }
+ case MONO_TYPE_PTR:
case MONO_TYPE_FNPTR:
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY:
case MONO_TYPE_U:
printf ("EAX=%d", eax);
break;
- case MONO_TYPE_STRING:
- printf ("[STRING:%s]", mono_string_to_utf8 ((MonoString *)(eax)));
+ case MONO_TYPE_STRING: {
+ MonoString *s = (MonoString *)eax;
+
+ if (s) {
+ g_assert (((MonoObject *)s)->klass == mono_defaults.string_class);
+ printf ("[STRING:%p:%s]", s, mono_string_to_utf8 (s));
+ } else
+ printf ("[STRING:null], ");
break;
+ }
case MONO_TYPE_OBJECT: {
MonoObject *o = (MonoObject *)eax;
x86_ret (cfg->code);
}
+/*
+ * get_unbox_trampoline:
+ * @m: method pointer
+ *
+ * when value type methods are called through the vtable we need to unbox the
+ * this argument. This method returns a pointer to a trampoline which does
+ * unboxing before calling the method
+ */
+static gpointer
+get_unbox_trampoline (MonoMethod *m)
+{
+ gpointer p = arch_compile_method (m);
+ guint8 *code, *start;
+ int this_pos = 4;
+
+ if (!m->signature->ret->byref && m->signature->ret->type == MONO_TYPE_VALUETYPE)
+ this_pos = 8;
+
+ start = code = g_malloc (16);
+
+ x86_alu_membase_imm (code, X86_ADD, X86_ESP, this_pos, sizeof (MonoObject));
+ x86_jump_code (code, p);
+ g_assert ((code - start) < 16);
+
+ return start;
+}
+
/**
* x86_magic_trampoline:
* @eax: saved x86 register
o += disp;
- return *((gpointer *)o) = arch_compile_method (m);
+ if (m->klass->valuetype) {
+ return *((gpointer *)o) = get_unbox_trampoline (m);
+ } else
+ return *((gpointer *)o) = arch_compile_method (m);
}
/**
if (mono_jit_dump_forest) {
int i;
+ printf ("FOREST %s.%s:%s\n", method->klass->name_space,
+ method->klass->name, method->name);
for (i = 0; i < cfg->block_count; i++) {
printf ("BLOCK %d:\n", i);
mono_print_forest (cfg->bblocks [i].forest);
method->klass->name, method->name, method, method->addr);
}
+
return method->addr;
}
for (i = 0; i < ji->num_clauses; i++) {
MonoJitExceptionInfo *ei = &ji->clauses [i];
- if (ei->try_start <= ip && ip < (ei->try_end)) {
-
+ if (ei->try_start <= ip && ip <= (ei->try_end)) {
/* catch block */
if (ei->flags == 0 && mono_object_isinst (obj,
mono_class_get (m->klass->image, ei->token_or_filter))) {
break; \
}
+#define MAKE_CMP(name) \
+case CEE_##name: { \
+ ++ip; \
+ sp -= 2; \
+ t1 = mono_ctree_new (mp, MB_TERM_##name, sp [0], sp [1]); \
+ g_assert (sp [0]->svt == sp [1]->svt); \
+ PUSH_TREE (t1, VAL_I32); \
+ break; \
+}
+
#define MAKE_SPILLED_BI_ALU(name) \
case CEE_##name: { \
++ip; \
static int
mono_allocate_intvar (MonoFlowGraph *cfg, int slot, MonoValueType type)
{
- int size, align, vnum;
+ int size, align, vnum, pos;
g_assert (type != VAL_UNKNOWN);
- if ((vnum = cfg->intvars [type - 1 + slot * VAL_DOUBLE]))
- return vnum;
+ /* take care if you modify MonoValueType */
+ g_assert (VAL_DOUBLE == 4);
+
+ /* fixme: machine dependant */
+ if (type == VAL_POINTER)
+ type = VAL_I32; /* VAL_I32 and VAL_POINTER share the same slot */
+ pos = type - 1 + slot * VAL_DOUBLE;
+
+ if ((vnum = cfg->intvars [pos]))
+ return vnum;
mono_get_val_sizes (type, &size, &align);
- return cfg->intvars[type - 1 + slot * VAL_DOUBLE] = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, type);
+ cfg->intvars[pos] = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, type);
+
+ return cfg->intvars[pos];
}
static int
ctree_create_load (MonoFlowGraph *cfg, MonoType *type, MBTree *addr, MonoValueType *svt, gboolean arg)
{
MonoMemPool *mp = cfg->mp;
- int ldind, size, align, vnum;
+ int ldind;
MBTree *t;
- if (!type->byref && type->type == MONO_TYPE_VALUETYPE &&
- !type->data.klass->enumtype) {
- size = mono_type_size (type, &align);
-
- vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
- t = mono_ctree_new (mp, MB_TERM_LDIND_OBJ, addr, NULL);
- t->data.i = vnum;
- return t;
- }
-
if (arg)
ldind = map_ldarg_type (type, svt);
else
t = mono_ctree_new (mp, stind, addr, s);
- if (type->type == MONO_TYPE_VALUETYPE) {
- guint32 align;
- t->data.i = mono_class_value_size (type->data.klass, &align);
- }
-
+ if (!type->byref && type->type == MONO_TYPE_VALUETYPE)
+ t->data.i = mono_class_value_size (type->data.klass, NULL);
+
return t;
}
{
MonoMemPool *mp = cfg->mp;
MBTree *t;
- int vnum;
+ int vnum = 0;
switch (s->op) {
case MB_TERM_STIND_I1:
case CEE_LDFLDA:
case CEE_STSFLD:
case CEE_STFLD:
+ case CEE_STOBJ:
case CEE_LDELEMA:
case CEE_NEWOBJ:
case CEE_CPOBJ:
for (i = 0; i < cfg->block_count; i++) {
bb = &cfg->bblocks [i];
- //printf ("BBS %d %05x %05x %d %d %d\n", i, bb->cli_addr, bb->cli_addr + bb->length, bb->reached, bb->finished, superblock_end);
+ //printf ("BBS %d %05x %05x %d %d %d %s\n", i, bb->cli_addr, bb->cli_addr + bb->length, bb->reached, bb->finished, superblock_end, method->name);
if (!bb->reached && !superblock_end) {
MonoBBlock *sbb = &cfg->bblocks [i - 1];
PUSH_TREE (t1, svt);
break;
}
+ case CEE_STOBJ: {
+ guint32 token;
+ MonoClass *c;
+ int size;
+
+ ++ip;
+ token = read32 (ip);
+ ip += 4;
+ sp -= 2;
+
+ c = mono_class_get (image, token);
+ g_assert (c->valuetype);
+
+ size = mono_class_value_size (c, NULL);
+
+ t1 = mono_ctree_new (mp, MB_TERM_STIND_OBJ, sp [0], sp [1]);
+ t1->data.i = size;
+ ADD_TREE (t1, cli_addr);
+ break;
+ }
case CEE_LDSTR: {
MonoObject *o;
guint32 index;
this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
this->data.m = cm;
} else {
- if (cm->klass->valuetype)
+ if (cm->klass->valuetype) {
this = mono_ctree_new_leaf (mp, MB_TERM_NEWSTRUCT);
- else
+ this->data.i = mono_class_value_size (cm->klass, NULL);
+ } else {
this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
+ this->data.klass = cm->klass;
+ }
- this->data.klass = cm->klass;
this->svt = VAL_POINTER;
t1 = mono_store_tree (cfg, -1, this, &this);
for (i = csig->param_count - 1; i >= 0; i--) {
MonoType *type = cm->signature->params [i];
t1 = mono_ctree_new (mp, map_arg_type (type, FALSE), arg_sp [i], NULL);
- ADD_TREE (t1, cli_addr);
size = mono_type_size (type, &align);
+ t1->data.i = size;
+ ADD_TREE (t1, cli_addr);
args_size += (size + 3) & ~3;
}
for (i = nargs - 1; i >= 0; i--) {
MonoType *type = cm->signature->params [i];
t1 = mono_ctree_new (mp, map_arg_type (type, pinvoke), arg_sp [i], NULL);
- ADD_TREE (t1, cli_addr);
size = mono_type_size (type, &align);
+ t1->data.i = size;
+ ADD_TREE (t1, cli_addr);
args_size += (size + 3) & ~3;
// fixme: align value type arguments to 8 byte boundary on the stack
PUSH_TREE (t1, sp [0]->svt);
break;
}
+ case CEE_BR:
case CEE_BR_S: {
gint32 target;
+ int br_s = (*ip == CEE_BR_S);
++ip;
- target = cli_addr + 2 + (signed char) *ip;
-
+ if (br_s)
+ target = cli_addr + 2 + (signed char) *ip;
+ else
+ target = cli_addr + 5 + (gint32) read32(ip);
+
g_assert (target >= 0 && target <= header->code_size);
g_assert (bcinfo [target].is_block_start);
tbb = &cfg->bblocks [bcinfo [target].block_id];
t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
t1->data.p = tbb;
ADD_TREE (t1, cli_addr);
- ++ip;
-
- superblock_end = TRUE;
- break;
- }
- case CEE_BR: {
- gint32 target;
-
- ++ip;
- target = cli_addr + 5 + (gint32) read32(ip);
- g_assert (target >= 0 && target <= header->code_size);
- g_assert (bcinfo [target].is_block_start);
- tbb = &cfg->bblocks [bcinfo [target].block_id];
- create_outstack (cfg, bb, stack, sp - stack);
- mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
-
- t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
- t1->data.p = tbb;
- ADD_TREE (t1, cli_addr);
- ip += 4;
+ if (br_s)
+ ++ip;
+ else
+ ip += 4;
superblock_end = TRUE;
break;
}
+ case CEE_LEAVE:
case CEE_LEAVE_S: {
gint32 target;
MonoBBlock *hb;
+ int leave_s = (*ip == CEE_LEAVE_S);
++ip;
- target = cli_addr + 2 + (signed char) *ip;
-
+ if (leave_s)
+ target = cli_addr + 2 + (signed char) *ip;
+ else
+ target = cli_addr + 5 + (gint32) read32(ip);
+
g_assert (target >= 0 && target <= header->code_size);
g_assert (bcinfo [target].is_block_start);
tbb = &cfg->bblocks [bcinfo [target].block_id];
t1->data.p = tbb;
ADD_TREE (t1, cli_addr);
- ++ip;
+ if (leave_s)
+ ++ip;
+ else
+ ip += 4;
superblock_end = TRUE;
break;
break;
}
case CEE_RET: {
+ MonoType *ret = signature->ret;
+
ip++;
- if (signature->ret->type != MONO_TYPE_VOID) {
+ if (ret->type != MONO_TYPE_VOID) {
--sp;
- t1 = mono_ctree_new (mp, MB_TERM_RETV, *sp, NULL);
+ if (!ret->byref && ret->type == MONO_TYPE_VALUETYPE) {
+ int align;
+ t1 = mono_ctree_new (mp, MB_TERM_RET_OBJ, *sp, NULL);
+ t1->data.i = mono_class_value_size (ret->data.klass, &align);
+ } else {
+ t1 = mono_ctree_new (mp, MB_TERM_RET, *sp, NULL);
+ }
} else {
- t1 = mono_ctree_new_leaf (mp, MB_TERM_RET);
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_RET_VOID);
}
t1->last_instr = (ip == end);
case CEE_STARG_S: {
++ip;
--sp;
+
t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
t1->data.i = ARG_POS (*ip);
t1 = ctree_create_store (cfg, ARG_TYPE (*ip), t1, *sp, TRUE);
++ip;
switch (*ip) {
- MAKE_BI_ALU (CEQ)
- MAKE_BI_ALU (CLT)
+ MAKE_CMP (CEQ)
+ MAKE_CMP (CLT)
case CEE_RETHROW: {
++ip;
}
if ((depth = sp - stack)) {
- create_outstack (cfg, bb, stack, sp - stack);
+ //printf ("DEPTH %d %d\n", depth, sp [0]->op);
//mono_print_forest (forest);
- //printf ("DEPTH %d %d\n", depth, sp [0]->op);
+ create_outstack (cfg, bb, stack, sp - stack);
}
} else
} else {
res = mfunc ();
}
+
+ if (method->signature->ret->type == MONO_TYPE_VOID)
+ res = 0;
return res;
}
trace = mono_string_to_utf8 (str);
}
- g_warning ("unhandled exception \"%s\"", message);
+ g_warning ("unhandled exception %s.%s: \"%s\"", obj->klass->name_space,
+ obj->klass->name, message);
if (trace) {
g_printerr (trace);
%term LDIND_U4 LDIND_OBJ
%term STIND_I1 STIND_I2 STIND_I4 STIND_I8 STIND_R4 STIND_R8 STIND_OBJ
%term ADDR_L ADDR_G ARG_I4 ARG_I8 ARG_R4 ARG_R8 ARG_OBJ ARG_STRING CALL_I4 CALL_I8 CALL_R8 CALL_VOID
-%term BREAK SWITCH BR RET RETV ENDFINALLY
+%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
break;
}
-
+
PRINT_REG ("LDIND_I4", tree->reg1);
}
}
reg: NEWSTRUCT {
- MonoClass *klass = tree->data.klass;
-
- if (tree->reg1 != X86_EAX)
- x86_push_reg (s->code, X86_EAX);
- x86_push_reg (s->code, X86_ECX);
- x86_push_reg (s->code, X86_EDX);
-
- g_assert (klass->valuetype);
- g_assert (klass->inited);
+ int size = tree->data.i;
+ int sa;
+
+ g_assert (size > 0);
- x86_push_imm (s->code, (klass->instance_size - sizeof (MonoObject)));
- x86_call_code (s->code, mono_object_allocate);
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
+ sa = size + 3;
+ sa &= ~3;
- x86_pop_reg (s->code, X86_EDX);
- x86_pop_reg (s->code, X86_ECX);
- if (tree->reg1 != X86_EAX) {
- x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
- x86_pop_reg (s->code, X86_EAX);
- }
+ x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, sa);
+ x86_mov_reg_reg (s->code, tree->reg1, X86_ESP, 4);
}
reg: UNBOX (reg) {
- // fixme: add type check
+ guint8 *start = s->code, *l1, *l2, *l3, *le;
+ int i;
- if (tree->reg1 != tree->left->reg1)
- x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
- x86_alu_reg_imm (s->code, X86_ADD, tree->reg1, sizeof (MonoObject));
+ tree->is_jump = TRUE;
+ l1 = l2 = l3 = le = NULL;
+
+ for (i = 0; i < 2; i++) {
+ s->code = start;
+
+ if (tree->reg1 != tree->left->reg1)
+ x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
+
+ x86_alu_reg_imm (s->code, X86_CMP, tree->reg1, 0);
+ x86_branch8 (s->code, X86_CC_NE, l2 - l1, FALSE);
+ l1 = s->code;
+ x86_mov_reg_imm (s->code, X86_ECX, get_exception_null_reference ());
+ x86_call_code (s->code, get_throw_exception ());
+ l2 = s->code;
+ x86_alu_membase_imm (s->code, X86_CMP, tree->reg1, 0, ((int)(tree->data.klass)));
+ x86_branch8 (s->code, X86_CC_EQ, le - l3, FALSE);
+ l3 = s->code;
+ x86_mov_reg_imm (s->code, X86_ECX, get_exception_invalid_cast ());
+ x86_call_code (s->code, get_throw_exception ());
+ le = s->code;
+ x86_alu_reg_imm (s->code, X86_ADD, tree->reg1, sizeof (MonoObject));
+ }
}
reg: CASTCLASS (reg) {
x86_breakpoint (s->code);
}
-stmt: RETV (reg) {
+stmt: RET (reg) {
if (tree->left->reg1 != X86_EAX)
x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
}
}
-stmt: RET {
+stmt: RET_VOID {
if (!tree->last_instr) {
tree->is_jump = 1;
x86_jump32 (s->code, s->epilog - 5);
g_assert (tree->reg2 == X86_EDX);
}
-stmt: RETV (lreg) {
+stmt: RET (lreg) {
if (tree->left->reg1 != X86_EAX) {
if (tree->left->reg2 != X86_EAX) {
x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
x86_pop_reg (s->code, tree->reg1);
}
+reg: CEQ (freg, freg) {
+ int treg = tree->reg1;
+
+ if (treg != X86_EAX)
+ x86_push_reg (s->code, X86_EAX); // save EAX
+
+ x86_fcompp (s->code);
+ x86_fnstsw (s->code);
+ x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
+ x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
+ x86_set_reg (s->code, X86_CC_EQ, tree->reg1, TRUE);
+ x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
+
+ if (treg != X86_EAX)
+ x86_pop_reg (s->code, X86_EAX); // save EAX
+}
+
freg: CONV_R8 (freg) {
/* nothing to do */
}
x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
}
-stmt: RETV (freg) {
+stmt: RET (freg) {
if (!tree->last_instr) {
tree->is_jump = 1;
# support for value types
-stmt: STIND_OBJ (reg, LDIND_OBJ (reg)) {
- x86_push_reg (s->code, X86_EAX);
- x86_push_reg (s->code, X86_EDX);
- x86_push_reg (s->code, X86_ECX);
-
- g_assert (tree->data.i > 0);
- x86_push_imm (s->code, tree->data.i);
- x86_push_reg (s->code, tree->right->left->reg1);
- x86_push_reg (s->code, tree->left->reg1);
- x86_call_code (s->code, MEMCOPY);
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
-
- x86_pop_reg (s->code, X86_ECX);
- x86_pop_reg (s->code, X86_EDX);
- x86_pop_reg (s->code, X86_EAX);
+reg: LDIND_OBJ (reg) {
+ if (tree->left->reg1 != tree->reg1)
+ x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
}
stmt: STIND_OBJ (reg, reg) {
x86_push_imm (s->code, tree->left->data.i);
}
-stmt: ARG_OBJ (LDIND_OBJ (reg)) {
- int size = g_array_index (s->varinfo, MonoVarInfo, tree->left->data.i).size;
+stmt: ARG_OBJ (reg) {
+ int size = tree->data.i;
int sa;
+ g_assert (size > 0);
+
sa = size + 3;
sa &= ~3;
x86_push_reg (s->code, X86_ECX);
x86_push_imm (s->code, size);
- x86_push_reg (s->code, tree->left->left->reg1);
+ x86_push_reg (s->code, tree->left->reg1);
x86_lea_membase (s->code, X86_EAX, X86_ESP, 5*4);
x86_push_reg (s->code, X86_EAX);
x86_pop_reg (s->code, X86_EAX);
}
-stmt: RETV (LDIND_OBJ (reg)) {
- int size = g_array_index (s->varinfo, MonoVarInfo, tree->left->data.i).size;
+stmt: RET_OBJ (reg) {
+ int size = tree->data.i;
x86_push_imm (s->code, size);
- x86_push_reg (s->code, tree->left->left->reg1);
+ x86_push_reg (s->code, tree->left->reg1);
x86_push_membase (s->code, X86_EBP, 8);
x86_call_code (s->code, MEMCOPY);