#include <mono/metadata/object.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/appdomain.h>
+#include <mono/metadata/marshal.h>
#include <mono/arch/x86/x86-codegen.h>
#include "regset.h"
};
#undef OPDEF
+/* alignment of activation frames */
+#define MONO_FRAME_ALIGNMENT 4
+
void print_lmf (void);
#define MBTREE_TYPE MBTree
MonoClass *klass;
MonoClassField *field;
X86AddressInfo ainfo;
- MonoJitCallInfo ci;
MonoJitFieldInfo fi;
MonoJitBranchInfo bi;
+ MonoJitCallInfo call_info;
+ MonoJitArgumentInfo arg_info;
} data;
};
guint64 mono_llrem_un (guint64 a, guint64 b);
gpointer mono_ldsflda (MonoClass *klass, int offset);
+gpointer mono_ldvirtftn (MonoObject *this, int slot);
+gpointer mono_ldintftn (MonoObject *this, int slot);
+gpointer mono_ldftn (MonoMethod *method);
+
void mono_emit_fast_iconv(MBCGEN_TYPE* s, MBTREE_TYPE* tree);
void mono_emit_fast_iconv_i8(MBCGEN_TYPE* s, MBTREE_TYPE* tree);
debug_memcopy (void *dest, const void *src, size_t n);
#ifdef DEBUG
-#define MEMCOPY debug_memcpy
+#define MEMCOPY debug_memcopy
#define PRINT_REG(text,reg) REAL_PRINT_REG(text,reg)
#else
x86_call_code (s->code, 0); \
} while (0);
+#define X86_ARG_PAD(pad) do { \
+ if (pad) { \
+ if (pad == 4) \
+ x86_push_reg (s->code, X86_EAX); \
+ else \
+ x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, pad); \
+ } \
+} while (0)
+
+#define X86_CALL_END do { \
+ int size = tree->data.call_info.frame_size; \
+ if (size) \
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, size); \
+} while (0)
+
+#define X86_CALL_BEGIN do { \
+ int pad = tree->data.call_info.pad; \
+ X86_ARG_PAD (pad); \
+ if (tree->left->op != MB_TERM_NOP) { \
+ mono_assert (lreg >= 0); \
+ x86_push_reg (s->code, lreg); \
+ x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0); \
+ } \
+ if (tree->data.call_info.vtype_num) { \
+ int offset = VARINFO (s, tree->data.call_info.vtype_num).offset; \
+ x86_lea_membase (s->code, treg, X86_EBP, offset); \
+ x86_push_reg (s->code, treg); \
+ } \
+} while (0)
+
/* we use this macro to move one lreg to another - source and
destination may overlap, but the register allocator has to
make sure that ((d1 < d2) && (s1 < s2))
# terminal definitions
#
-# constatnts
+# constants
%term CONST_I4 CONST_I8 CONST_R4 CONST_R8
%term LDIND_I1 LDIND_U1 LDIND_I2 LDIND_U2 LDIND_I4 LDIND_I8 LDIND_R4 LDIND_R8 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_VOID RET RET_OBJ ENDFINALLY JMP
+%term ADDR_L ADDR_G ARG_I4 ARG_I8 ARG_R4 ARG_R8 ARG_OBJ CALL_I4 CALL_I8 CALL_R8 CALL_VOID
+%term BREAK SWITCH BR RET_VOID RET RET_OBJ ENDFINALLY ENDFILTER JMP
%term ADD ADD_OVF ADD_OVF_UN SUB SUB_OVF SUB_OVF_UN MUL MUL_OVF MUL_OVF_UN
%term DIV DIV_UN REM REM_UN AND OR XOR SHL SHR SHR_UN NEG NOT CKFINITE
%term COMPARE CBRANCH BRTRUE BRFALSE CSET
%term LDLEN LDELEMA LDFTN LDVIRTFTN LDSTR LDSFLDA
%term REMOTE_LDFLDA REMOTE_STIND_I1 REMOTE_STIND_I2 REMOTE_STIND_I4
%term REMOTE_STIND_I8 REMOTE_STIND_R4 REMOTE_STIND_R8 REMOTE_STIND_OBJ
+%term SIN COS SQRT
+
+%term FUNC1 PROC2 PROC3 FREE OBJADDR VTADDR
+
#
# we start at stmt
#
# we pass exception in ECX to catch handler
reg: EXCEPTION {
int offset = VARINFO (s, tree->data.i).offset;
- int reg = VARINFO (s, tree->data.i).reg;
if (tree->reg1 != X86_ECX)
x86_mov_reg_reg (s->code, tree->reg1, X86_ECX, 4);
/* store it so that we can RETHROW it later */
- if (reg < 0)
- x86_mov_membase_reg (s->code, X86_EBP, offset, tree->reg1, 4);
- else
- x86_mov_reg_reg (s->code, reg, tree->reg1, 4);
+ x86_mov_membase_reg (s->code, X86_EBP, offset, tree->reg1, 4);
}
stmt: THROW (reg) {
}
stmt: RETHROW {
- int off = VARINFO (s, tree->data.i).offset;
- int reg = VARINFO (s, tree->data.i).reg;
+ int offset = VARINFO (s, tree->data.i).offset;
gpointer target;
- if (reg < 0)
- x86_push_membase (s->code, X86_EBP, off);
- else
- x86_push_reg (s->code, reg);
+ x86_push_membase (s->code, X86_EBP, offset);
target = arch_get_throw_exception ();
mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, target);
stmt: HANDLER {
/* save ESP (used by ENDFINALLY) */
- x86_mov_membase_reg (s->code, X86_EBP, -16, X86_ESP, 4);
+ x86_mov_membase_reg (s->code, X86_EBP, mono_exc_esp_offset, X86_ESP, 4);
mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
x86_call_imm (s->code, 0);
}
stmt: ENDFINALLY {
- /* restore ESP - which an be modified when we allocate value types
+ /* restore ESP - which can be modified when we allocate value types
* in the finally handler */
- x86_mov_reg_membase (s->code, X86_ESP, X86_EBP, -16, 4);
+ x86_mov_reg_membase (s->code, X86_ESP, X86_EBP, mono_exc_esp_offset, 4);
+ x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
+ x86_ret (s->code);
+}
+
+stmt: ENDFILTER (reg) {
+ /* restore ESP - which can be modified when we allocate value types
+ * in the filter */
+ x86_mov_reg_membase (s->code, X86_ESP, X86_EBP, mono_exc_esp_offset, 4);
x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
+ if (tree->left->reg1 != X86_EAX)
+ x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
x86_ret (s->code);
}
x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
}
-# warning: this chain rule requires a register
reg: CONST_I4 1 {
x86_mov_reg_imm (s->code, tree->reg1, tree->data.i);
}
x86_push_imm (s->code, tree->data.p);
mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_array_new_wrapper);
x86_call_code (s->code, 0);
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer) + 4);
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
x86_pop_reg (s->code, X86_EDX);
x86_pop_reg (s->code, X86_ECX);
x86_push_imm (s->code, tree->data.p);
mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_array_new_specific);
x86_call_code (s->code, 0);
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer) + 4);
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
x86_pop_reg (s->code, X86_EDX);
x86_pop_reg (s->code, X86_ECX);
x86_push_imm (s->code, tree->data.klass);
mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_object_new_wrapper);
x86_call_code (s->code, 0);
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
x86_pop_reg (s->code, X86_EDX);
x86_pop_reg (s->code, X86_ECX);
x86_push_imm (s->code, tree->data.p);
mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_object_new_specific);
x86_call_code (s->code, 0);
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
x86_pop_reg (s->code, X86_EDX);
x86_pop_reg (s->code, X86_ECX);
PRINT_REG ("NEWOBJ_SPEC", tree->reg1);
}
-reg: LOCALLOC (reg) {
+reg: OBJADDR (reg) {
+ if (tree->left->reg1 != tree->reg1)
+ x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
+}
+
+reg: VTADDR (ADDR_L) {
+ int offset = VARINFO (s, tree->left->data.i).offset;
+
+ x86_lea_membase (s->code, tree->reg1, X86_EBP, offset);
+}
+
+stmt: FREE (reg) {
+ x86_push_reg (s->code, tree->left->reg1);
+ mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, g_free);
+ x86_call_code (s->code, 0);
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
+}
+
+stmt: PROC2 (reg, reg) {
+ x86_push_reg (s->code, tree->right->reg1);
+ x86_push_reg (s->code, tree->left->reg1);
+ mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->data.p);
+ x86_call_code (s->code, 0);
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
+}
+
+stmt: PROC3 (reg, CPSRC (reg, reg)) {
+ x86_push_reg (s->code, tree->right->right->reg1);
+ x86_push_reg (s->code, tree->right->left->reg1);
+ x86_push_reg (s->code, tree->left->reg1);
+ mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->data.p);
+ x86_call_code (s->code, 0);
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
+}
+
+reg: FUNC1 (reg) {
+ 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);
+
+ x86_push_reg (s->code, tree->left->reg1);
+
+ mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->data.p);
+ x86_call_code (s->code, 0);
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
+
+ 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);
+ }
+}
- /* size must be aligne to 4 bytes */
- x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, 3);
- x86_alu_reg_imm (s->code, X86_AND, tree->left->reg1, ~3);
+
+reg: LOCALLOC (reg) {
+ int offset = 0;
+ /* size must be aligned to MONO_FRAME_ALIGNMENT bytes */
+ x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, MONO_FRAME_ALIGNMENT - 1);
+ x86_alu_reg_imm (s->code, X86_AND, tree->left->reg1, ~(MONO_FRAME_ALIGNMENT - 1));
/* allocate space on stack */
x86_alu_reg_reg (s->code, X86_SUB, X86_ESP, tree->left->reg1);
if (tree->data.i) {
/* initialize with zero */
-
- if (tree->reg1 != X86_EAX && tree->left->reg1 != X86_EAX)
+ if (tree->reg1 != X86_EAX && tree->left->reg1 != X86_EAX) {
x86_push_reg (s->code, X86_EAX);
- if (tree->reg1 != X86_ECX && tree->left->reg1 != X86_ECX)
+ offset += 4;
+ }
+ if (tree->reg1 != X86_ECX && tree->left->reg1 != X86_ECX) {
x86_push_reg (s->code, X86_ECX);
-
+ offset += 4;
+ }
+ if (tree->reg1 != X86_EDI && tree->left->reg1 != X86_EDI) {
+ x86_push_reg (s->code, X86_EDI);
+ offset += 4;
+ }
+
x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg1, 2);
if (tree->left->reg1 != X86_ECX)
x86_mov_reg_imm (s->code, X86_ECX, tree->left->reg1);
x86_alu_reg_reg (s->code, X86_XOR, X86_EAX, X86_EAX);
+
+ x86_lea_membase (s->code, X86_EDI, X86_ESP, offset);
x86_cld (s->code);
x86_prefix (s->code, X86_REP_PREFIX);
x86_stosl (s->code);
+ if (tree->reg1 != X86_EDI && tree->left->reg1 != X86_EDI)
+ x86_pop_reg (s->code, X86_EDI);
if (tree->reg1 != X86_ECX && tree->left->reg1 != X86_ECX)
x86_pop_reg (s->code, X86_ECX);
if (tree->reg1 != X86_EAX && tree->left->reg1 != X86_EAX)
stmt: INITOBJ (reg) {
int i, j;
- i = tree->data.i;
+ if (!(i = tree->data.i))
+ return;
if (i == 1 || i == 2 || i == 4) {
x86_mov_membase_imm (s->code, tree->left->reg1, 0, 0, i);
i = tree->data.i / 4;
j = tree->data.i % 4;
- x86_push_reg (s->code, X86_EAX);
-
if (tree->left->reg1 != X86_EDI) {
x86_push_reg (s->code, X86_EDI);
x86_mov_reg_reg (s->code, X86_EDI, tree->left->reg1, 4);
}
if (i) {
- x86_push_reg (s->code, X86_ECX);
x86_alu_reg_reg (s->code, X86_XOR, X86_EAX, X86_EAX);
x86_mov_reg_imm (s->code, X86_ECX, i);
x86_cld (s->code);
x86_prefix (s->code, X86_REP_PREFIX);
x86_stosl (s->code);
- x86_pop_reg (s->code, X86_ECX);
for (i = 0; i < j; i++)
x86_stosb (s->code);
if (tree->left->reg1 != X86_EDI)
x86_pop_reg (s->code, X86_EDI);
+}
+
+stmt: CPBLK (reg, CPSRC (reg, CONST_I4)) {
+ int dest_reg = tree->left->reg1;
+ int source_reg = tree->right->left->reg1;
+ int count = tree->right->right->data.i;
+ int sreg = dest_reg != X86_EAX ? X86_EAX : X86_EDX;
+ int spill_pos = 0, dest_offset = 0, source_offset = 0;
+ int save_esi = FALSE, save_edi = FALSE;
+
+ // TODO: handle unaligned. prefix
+
+ switch (count) {
+ case 0:
+ break;
+ case 1:
+ x86_mov_reg_membase (s->code, sreg, source_reg, 0, 1);
+ x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 1);
+ break;
+ case 2:
+ x86_mov_reg_membase (s->code, sreg, source_reg, 0, 2);
+ x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 2);
+ break;
+ case 3:
+ x86_mov_reg_membase (s->code, sreg, source_reg, 0, 2);
+ x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 2);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 2, 1);
+ x86_mov_membase_reg (s->code, dest_reg, 2, sreg, 1);
+ break;
+ case 4:
+ x86_mov_reg_membase (s->code, sreg, source_reg, 0, 4);
+ x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 4);
+ break;
+ case 5:
+ x86_mov_reg_membase (s->code, sreg, source_reg, 0, 4);
+ x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 4);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 4, 1);
+ x86_mov_membase_reg (s->code, dest_reg, 4, sreg, 1);
+ break;
+ case 6:
+ x86_mov_reg_membase (s->code, sreg, source_reg, 0, 4);
+ x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 4);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 4, 2);
+ x86_mov_membase_reg (s->code, dest_reg, 4, sreg, 2);
+ break;
+ case 7:
+ x86_mov_reg_membase (s->code, sreg, source_reg, 0, 4);
+ x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 4);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 4, 2);
+ x86_mov_membase_reg (s->code, dest_reg, 4, sreg, 2);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 6, 1);
+ x86_mov_membase_reg (s->code, dest_reg, 6, sreg, 1);
+ break;
+ case 8:
+ x86_fild_membase (s->code, source_reg, 0, TRUE);
+ x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+ break;
+ case 9:
+ x86_fild_membase (s->code, source_reg, 0, TRUE);
+ x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 8, 1);
+ x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 1);
+ break;
+ case 10:
+ x86_fild_membase (s->code, source_reg, 0, TRUE);
+ x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 8, 2);
+ x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 2);
+ break;
+ case 11:
+ x86_fild_membase (s->code, source_reg, 0, TRUE);
+ x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 8, 2);
+ x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 2);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 10, 1);
+ x86_mov_membase_reg (s->code, dest_reg, 10, sreg, 1);
+ break;
+ case 12:
+ x86_fild_membase (s->code, source_reg, 0, TRUE);
+ x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 8, 4);
+ x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 4);
+ break;
+ case 13:
+ x86_fild_membase (s->code, source_reg, 0, TRUE);
+ x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 8, 4);
+ x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 4);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 12, 1);
+ x86_mov_membase_reg (s->code, dest_reg, 12, sreg, 1);
+ break;
+ case 14:
+ x86_fild_membase (s->code, source_reg, 0, TRUE);
+ x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 8, 4);
+ x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 4);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 12, 2);
+ x86_mov_membase_reg (s->code, dest_reg, 12, sreg, 2);
+ break;
+ case 15:
+ x86_fild_membase (s->code, source_reg, 0, TRUE);
+ x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 8, 4);
+ x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 4);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 12, 2);
+ x86_mov_membase_reg (s->code, dest_reg, 12, sreg, 2);
+ x86_mov_reg_membase (s->code, sreg, source_reg, 14, 1);
+ x86_mov_membase_reg (s->code, dest_reg, 14, sreg, 1);
+ break;
+ default:
+ g_assert (count > 15);
+
+ if (dest_reg != X86_ESI && source_reg != X86_ESI &&
+ mono_regset_reg_used (s->rs, X86_ESI))
+ save_esi = TRUE;
+ if (dest_reg != X86_EDI && source_reg != X86_EDI &&
+ mono_regset_reg_used (s->rs, X86_EDI))
+ save_edi = TRUE;
+
+ if (save_esi)
+ x86_push_reg (s->code, X86_ESI);
+ if (save_edi)
+ x86_push_reg (s->code, X86_EDI);
+
+ if (dest_reg == X86_ESI) {
+ dest_offset = ++spill_pos;
+ }
+ if (source_reg == X86_EDI) {
+ source_offset = ++spill_pos;
+ }
+
+ if (source_offset)
+ x86_push_reg (s->code, source_reg);
+ if (dest_offset)
+ x86_push_reg (s->code, dest_reg);
- x86_pop_reg (s->code, X86_EAX);
+ if (source_reg != X86_ESI) {
+ if (source_offset)
+ x86_mov_reg_membase (s->code, X86_ESI, X86_ESP, (source_offset-1)<<2, 4);
+ else
+ x86_mov_reg_reg (s->code, X86_ESI, source_reg, 4);
+ }
+ if (dest_reg != X86_EDI) {
+ if (dest_offset)
+ x86_mov_reg_membase (s->code, X86_EDI, X86_ESP, (dest_offset-1)<<2, 4);
+ else
+ x86_mov_reg_reg (s->code, X86_EDI, dest_reg, 4);
+ }
+
+ x86_mov_reg_imm (s->code, X86_ECX, count >> 2);
+ x86_cld (s->code);
+ x86_prefix (s->code, X86_REP_PREFIX);
+ x86_movsd (s->code);
+
+ switch (count & 3) {
+ case 1:
+ x86_mov_reg_membase (s->code, sreg, X86_ESI, 0, 1);
+ x86_mov_membase_reg (s->code, X86_EDI, 0, sreg, 1);
+ break;
+ case 2:
+ x86_mov_reg_membase (s->code, sreg, X86_ESI, 0, 2);
+ x86_mov_membase_reg (s->code, X86_EDI, 0, sreg, 2);
+ break;
+ case 3:
+ x86_mov_reg_membase (s->code, sreg, X86_ESI, 0, 2);
+ x86_mov_membase_reg (s->code, X86_EDI, 0, sreg, 2);
+ x86_mov_reg_membase (s->code, sreg, X86_ESI, 2, 1);
+ x86_mov_membase_reg (s->code, X86_EDI, 2, sreg, 1);
+ break;
+ default:
+ break;
+ }
+
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, spill_pos<<2);
+
+ if (save_edi)
+ x86_pop_reg (s->code, X86_EDI);
+ if (save_esi)
+ x86_pop_reg (s->code, X86_ESI);
+
+ break;
+ }
+} cost {
+ MBCOND (mono_inline_memcpy);
+ return 0;
}
stmt: CPBLK (reg, CPSRC (reg, reg)) {
int dest_reg = tree->left->reg1;
int source_reg = tree->right->left->reg1;
int size_reg = tree->right->right->reg1;
+ int spill_pos = 0, size_offset = 0, dest_offset = 0, source_offset = 0;
+ int save_esi = FALSE, save_edi = FALSE;
+
+ if (!mono_inline_memcpy) {
+ x86_push_reg (s->code, size_reg);
+ x86_push_reg (s->code, source_reg);
+ x86_push_reg (s->code, dest_reg);
+ mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, memmove);
+ x86_call_code (s->code, 0);
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
+ } else {
+ if (dest_reg != X86_ESI && source_reg != X86_ESI && size_reg != X86_ESI &&
+ mono_regset_reg_used (s->rs, X86_ESI))
+ save_esi = TRUE;
+ if (dest_reg != X86_EDI && source_reg != X86_EDI && size_reg != X86_EDI &&
+ mono_regset_reg_used (s->rs, X86_EDI))
+ save_edi = TRUE;
+
+ if (save_esi)
+ x86_push_reg (s->code, X86_ESI);
+ if (save_edi)
+ x86_push_reg (s->code, X86_EDI);
+
+ if (size_reg == X86_EDI || size_reg == X86_ESI) {
+ size_offset = ++spill_pos;
+ }
+ if (dest_reg == X86_ECX || dest_reg == X86_ESI) {
+ dest_offset = ++spill_pos;
+ }
+ if (source_reg == X86_ECX || source_reg == X86_EDI) {
+ source_offset = ++spill_pos;
+ }
+
+ if (source_offset)
+ x86_push_reg (s->code, source_reg);
+ if (dest_offset)
+ x86_push_reg (s->code, dest_reg);
+ if (size_offset)
+ x86_push_reg (s->code, size_reg);
+
+ if (source_reg != X86_ESI) {
+ if (source_offset)
+ x86_mov_reg_membase (s->code, X86_ESI, X86_ESP, (source_offset-1)<<2, 4);
+ else
+ x86_mov_reg_reg (s->code, X86_ESI, source_reg, 4);
+ }
+ if (dest_reg != X86_EDI) {
+ if (dest_offset)
+ x86_mov_reg_membase (s->code, X86_EDI, X86_ESP, (dest_offset-1)<<2, 4);
+ else
+ x86_mov_reg_reg (s->code, X86_EDI, dest_reg, 4);
+ }
+ if (size_reg != X86_ECX) {
+ if (size_offset)
+ x86_mov_reg_membase (s->code, X86_ECX, X86_ESP, (size_offset-1)<<2, 4);
+ else
+ x86_mov_reg_reg (s->code, X86_ECX, size_reg, 4);
+ }
- x86_push_reg (s->code, size_reg);
- x86_push_reg (s->code, source_reg);
- x86_push_reg (s->code, dest_reg);
- mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, memmove);
- x86_call_code (s->code, 0);
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
+ x86_push_reg (s->code, X86_ECX);
+ x86_shift_reg_imm (s->code, X86_SHR, X86_ECX, 2);
+
+ x86_cld (s->code);
+
+ // move whole dwords first
+ x86_prefix (s->code, X86_REP_PREFIX);
+ x86_movsd (s->code);
+
+ x86_pop_reg (s->code, X86_ECX);
+ x86_alu_reg_imm (s->code, X86_AND, X86_ECX, 3);
+
+ // move remaining bytes (if any)
+ x86_prefix (s->code, X86_REP_PREFIX);
+ x86_movsb (s->code);
+
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, spill_pos<<2);
+
+ if (save_edi)
+ x86_pop_reg (s->code, X86_EDI);
+ if (save_esi)
+ x86_pop_reg (s->code, X86_ESI);
+ }
+}
+
+stmt: INITBLK (reg, CPSRC (reg, CONST_I4)) {
+ int dest_reg = tree->left->reg1;
+ int value_reg = tree->right->left->reg1;
+ int size = tree->right->right->data.i;
+ int spill_pos = 0, dest_offset = 0, value_offset = 0;
+ int save_edi = FALSE;
+ int i, j;
+
+ i = size / 4;
+ j = size % 4;
+
+ if (mono_inline_memcpy) {
+
+ if (dest_reg != X86_EDI && value_reg != X86_EDI &&
+ mono_regset_reg_used (s->rs, X86_EDI)) {
+ save_edi = TRUE;
+ x86_push_reg (s->code, X86_EDI);
+ }
+
+ if (dest_reg == X86_ECX || dest_reg == X86_EAX) {
+ dest_offset = ++spill_pos;
+ }
+ if (value_reg == X86_ECX || value_reg == X86_EDI) {
+ value_offset = ++spill_pos;
+ }
+
+ if (value_offset)
+ x86_push_reg (s->code, value_reg);
+ if (dest_offset)
+ x86_push_reg (s->code, dest_reg);
+
+ if (value_reg != X86_EAX) {
+ if (value_offset)
+ x86_mov_reg_membase (s->code, X86_EAX, X86_ESP, (value_offset-1)<<2, 4);
+ else
+ x86_mov_reg_reg (s->code, X86_EAX, value_reg, 4);
+ }
+ if (dest_reg != X86_EDI) {
+ if (dest_offset)
+ x86_mov_reg_membase (s->code, X86_EDI, X86_ESP, (dest_offset-1)<<2, 4);
+ else
+ x86_mov_reg_reg (s->code, X86_EDI, dest_reg, 4);
+ }
+
+ x86_widen_reg (s->code, X86_EAX, X86_EAX, FALSE, FALSE);
+ x86_mov_reg_reg (s->code, X86_EDX, X86_EAX, 4);
+ x86_shift_reg_imm (s->code, X86_SHL, X86_EAX, 8);
+ x86_alu_reg_reg (s->code, X86_OR, X86_EAX, X86_EDX);
+ x86_mov_reg_reg (s->code, X86_EDX, X86_EAX, 4);
+ x86_shift_reg_imm (s->code, X86_SHL, X86_EAX, 16);
+ x86_alu_reg_reg (s->code, X86_OR, X86_EAX, X86_EDX);
+
+ if (i) {
+ x86_mov_reg_imm (s->code, X86_ECX, i);
+ x86_cld (s->code);
+ x86_prefix (s->code, X86_REP_PREFIX);
+ x86_stosd (s->code);
+ }
+
+ for (i = 0; i < j; i++)
+ x86_stosb (s->code);
+
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, spill_pos<<2);
+
+ if (save_edi)
+ x86_pop_reg (s->code, X86_EDI);
+
+ } else {
+ x86_push_imm (s->code, size);
+ x86_push_reg (s->code, value_reg);
+ x86_push_reg (s->code, dest_reg);
+ mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, memset);
+ x86_call_code (s->code, 0);
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
+ }
+} cost {
+ MBCOND (mono_inline_memcpy);
+ return 0;
}
stmt: INITBLK (reg, CPSRC (reg, reg)) {
int dest_reg = tree->left->reg1;
- int source_reg = tree->right->left->reg1;
+ int value_reg = tree->right->left->reg1;
int size_reg = tree->right->right->reg1;
+ int spill_pos = 0, size_offset = 0, dest_offset = 0, value_offset = 0;
+ int save_edi = FALSE;
- x86_push_reg (s->code, size_reg);
- x86_push_reg (s->code, source_reg);
- x86_push_reg (s->code, dest_reg);
- mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, memset);
- x86_call_code (s->code, 0);
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
+ if (mono_inline_memcpy) {
+
+ if (dest_reg != X86_EDI && size_reg != X86_EDI && size_reg != X86_EDI &&
+ mono_regset_reg_used (s->rs, X86_EDI)) {
+ save_edi = TRUE;
+ x86_push_reg (s->code, X86_EDI);
+ }
+
+ if (size_reg == X86_EDI || size_reg == X86_EAX) {
+ size_offset = ++spill_pos;
+ }
+ if (dest_reg == X86_ECX || dest_reg == X86_EAX) {
+ dest_offset = ++spill_pos;
+ }
+ if (value_reg == X86_ECX || value_reg == X86_EDI) {
+ value_offset = ++spill_pos;
+ }
+
+ if (value_offset)
+ x86_push_reg (s->code, value_reg);
+ if (dest_offset)
+ x86_push_reg (s->code, dest_reg);
+ if (size_offset)
+ x86_push_reg (s->code, size_reg);
+
+ if (value_reg != X86_EAX) {
+ if (value_offset)
+ x86_mov_reg_membase (s->code, X86_EAX, X86_ESP, (value_offset-1)<<2, 4);
+ else
+ x86_mov_reg_reg (s->code, X86_EAX, value_reg, 4);
+ }
+ if (dest_reg != X86_EDI) {
+ if (dest_offset)
+ x86_mov_reg_membase (s->code, X86_EDI, X86_ESP, (dest_offset-1)<<2, 4);
+ else
+ x86_mov_reg_reg (s->code, X86_EDI, dest_reg, 4);
+ }
+ if (size_reg != X86_ECX) {
+ if (size_offset)
+ x86_mov_reg_membase (s->code, X86_ECX, X86_ESP, (size_offset-1)<<2, 4);
+ else
+ x86_mov_reg_reg (s->code, X86_ECX, size_reg, 4);
+ }
+
+ x86_widen_reg (s->code, X86_EAX, X86_EAX, FALSE, FALSE);
+ x86_mov_reg_reg (s->code, X86_EDX, X86_EAX, 4);
+ x86_shift_reg_imm (s->code, X86_SHL, X86_EAX, 8);
+ x86_alu_reg_reg (s->code, X86_OR, X86_EAX, X86_EDX);
+ x86_mov_reg_reg (s->code, X86_EDX, X86_EAX, 4);
+ x86_shift_reg_imm (s->code, X86_SHL, X86_EAX, 16);
+ x86_alu_reg_reg (s->code, X86_OR, X86_EAX, X86_EDX);
+
+ x86_push_reg (s->code, X86_ECX);
+ x86_shift_reg_imm (s->code, X86_SHR, X86_ECX, 2);
+ x86_cld (s->code);
+
+ // init whole dwords first
+ x86_prefix (s->code, X86_REP_PREFIX);
+ x86_stosd (s->code);
+
+ x86_pop_reg (s->code, X86_ECX);
+ x86_alu_reg_imm (s->code, X86_AND, X86_ECX, 3);
+
+ // init remaining bytes (if any)
+ x86_prefix (s->code, X86_REP_PREFIX);
+ x86_stosb (s->code);
+
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, spill_pos<<2);
+
+ if (save_edi)
+ x86_pop_reg (s->code, X86_EDI);
+
+ } else {
+ x86_push_reg (s->code, size_reg);
+ x86_push_reg (s->code, value_reg);
+ x86_push_reg (s->code, dest_reg);
+ mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, memset);
+ x86_call_code (s->code, 0);
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
+ }
}
stmt: NOP
}
}
-
stmt: ARG_I4 (LDIND_I4 (addr)) {
MBTree *at = tree->left->left;
+ int pad = tree->data.arg_info.pad;
+
+ X86_ARG_PAD (pad);
switch (at->data.ainfo.amode) {
stmt: ARG_I4 (LDIND_I4 (ADDR_L)) {
int treg = VARINFO (s, tree->left->left->data.i).reg;
+ int pad = tree->data.arg_info.pad;
+
+ X86_ARG_PAD (pad);
x86_push_reg (s->code, treg);
} cost {
MBCOND ((VARINFO (data, tree->left->left->data.i).reg >= 0));
}
stmt: ARG_I4 (reg) {
- x86_push_reg (s->code, tree->left->reg1);
- PRINT_REG ("ARG_I4", tree->left->reg1);
-}
-
-# fixme: we must free the allocated strings somewhere
-stmt: ARG_STRING (reg) {
- x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
- x86_push_reg (s->code, X86_EAX);
- x86_push_reg (s->code, X86_ECX);
- x86_push_reg (s->code, X86_EDX);
+ int pad = tree->data.arg_info.pad;
+ X86_ARG_PAD (pad);
x86_push_reg (s->code, tree->left->reg1);
- mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_string_to_utf8);
- x86_call_code (s->code, 0);
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
-
- x86_mov_membase_reg (s->code, X86_ESP, 12, X86_EAX, 4);
-
- x86_pop_reg (s->code, X86_EDX);
- x86_pop_reg (s->code, X86_ECX);
- x86_pop_reg (s->code, X86_EAX);
}
stmt: ARG_I4 (ADDR_G) {
+ int pad = tree->data.arg_info.pad;
+
+ X86_ARG_PAD (pad);
x86_push_imm (s->code, tree->left->data.p);
}
stmt: ARG_I4 (CONST_I4) "MB_USE_OPT1(0)" {
+ int pad = tree->data.arg_info.pad;
+
+ X86_ARG_PAD (pad);
x86_push_imm (s->code, tree->left->data.i);
}
if (lreg == treg || rreg == treg)
mono_assert_not_reached ();
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
x86_call_reg (s->code, rreg);
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
-
- PRINT_REG ("CALL_I4", tree->reg1);
+ X86_CALL_END;
mono_assert (tree->reg1 == X86_EAX);
}
if (lreg == treg)
treg = X86_EDX;
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
x86_call_code (s->code, 0);
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
-
- PRINT_REG ("CALL_I4", tree->reg1);
+ X86_CALL_END;
mono_assert (tree->reg1 == X86_EAX);
}
reg: LDVIRTFTN (reg, INTF_ADDR) {
- int lreg = tree->left->reg1;
+ /* we cant return the value in the vtable, because it can be
+ * a magic trampoline, and we cant pass that to the outside world */
+
+ 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);
- x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
- x86_mov_reg_membase (s->code, lreg, lreg,
- G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
- x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
- x86_mov_reg_membase (s->code, tree->reg1, lreg, tree->right->data.m->slot << 2, 4);
+ x86_push_imm (s->code, tree->right->data.m->klass->interface_id);
+ x86_push_reg (s->code, tree->left->reg1);
+ mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldintftn);
+ x86_call_code (s->code, 0);
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
+
+ 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);
+ }
}
reg: CALL_I4 (this, INTF_ADDR) {
if (lreg == treg)
treg = X86_EDX;
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_mov_reg_membase (s->code, lreg, lreg,
x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
-
- PRINT_REG ("CALL_I4(INTERFACE)", tree->reg1);
+ X86_CALL_END;
mono_assert (tree->reg1 == X86_EAX);
}
reg: LDVIRTFTN (reg, VFUNC_ADDR) {
- int lreg = tree->left->reg1;
-
- x86_mov_reg_membase (s->code, tree->reg1, lreg, 0, 4);
+ /* we cant return the value in the vtable, because it can be
+ * a magic trampoline, and we cant pass that to the outside world */
- x86_mov_reg_membase (s->code, tree->reg1, tree->reg1, G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2), 4);
+ 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);
+
+ x86_push_imm (s->code, tree->right->data.m->slot);
+ x86_push_reg (s->code, tree->left->reg1);
+ mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldvirtftn);
+ x86_call_code (s->code, 0);
+ x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
+
+ 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);
+ }
}
reg: LDFTN {
x86_push_reg (s->code, X86_EDX);
x86_push_imm (s->code, tree->data.m);
- mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_compile_method);
+ mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldftn);
x86_call_code (s->code, 0);
x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
x86_pop_reg (s->code, X86_EAX);
}
- PRINT_REG ("LDFTN", tree->reg1);
}
if (lreg == treg)
treg = X86_EDX;
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_call_virtual (s->code, lreg,
G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
-
- PRINT_REG ("CALL_I4(VIRTUAL)", tree->reg1);
+ X86_CALL_END;
mono_assert (tree->reg1 == X86_EAX);
}
if (lreg == treg)
treg = X86_EDX;
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
x86_call_code (s->code, 0);
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+ X86_CALL_END;
}
stmt: CALL_VOID (this, reg) {
- int lreg = tree->left->reg1;
int treg = X86_EAX;
+ int lreg = tree->left->reg1;
+ int rreg = tree->right->reg1;
- if (lreg == treg)
+ if (lreg == treg || rreg == treg)
treg = X86_EDX;
+ if (lreg == treg || rreg == treg)
+ treg = X86_ECX;
+ if (lreg == treg || rreg == treg)
+ mono_assert_not_reached ();
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
x86_call_reg (s->code, tree->right->reg1);
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+ X86_CALL_END;
}
stmt: CALL_VOID (this, INTF_ADDR) {
if (lreg == treg)
treg = X86_EDX;
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_mov_reg_membase (s->code, lreg, lreg,
x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+ X86_CALL_END;
}
stmt: CALL_VOID (this, VFUNC_ADDR) {
if (lreg == treg)
treg = X86_EDX;
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_call_virtual (s->code, lreg,
G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+ X86_CALL_END;
}
stmt: SWITCH (reg) {
tree->reg2 == X86_EDX);
}
+lreg: CALL_I8 (this, reg) {
+ int treg = X86_EAX;
+ int lreg = tree->left->reg1;
+ int rreg = tree->right->reg1;
+
+ if (lreg == treg || rreg == treg)
+ treg = X86_EDX;
+ if (lreg == treg || rreg == treg)
+ treg = X86_ECX;
+ if (lreg == treg || rreg == treg)
+ mono_assert_not_reached ();
+
+ X86_CALL_BEGIN;
+
+ x86_call_reg (s->code, rreg);
+
+ X86_CALL_END;
+
+ mono_assert (tree->reg1 == X86_EAX);
+ mono_assert (tree->reg2 == X86_EDX);
+}
+
lreg: CALL_I8 (this, ADDR_G) {
int lreg = tree->left->reg1;
int treg = X86_EAX;
if (lreg == treg)
treg = X86_EDX;
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
x86_call_code (s->code, 0);
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+ X86_CALL_END;
mono_assert (tree->reg1 == X86_EAX);
mono_assert (tree->reg2 == X86_EDX);
if (lreg == treg)
treg = X86_EDX;
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_call_virtual (s->code, lreg,
G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
-
- PRINT_REG ("CALL0_I8(VIRTUAL)", tree->reg1);
- PRINT_REG ("CALL1_I8(VIRTUAL)", tree->reg2);
+ X86_CALL_END;
mono_assert (tree->reg1 == X86_EAX);
mono_assert (tree->reg2 == X86_EDX);
if (lreg == treg)
treg = X86_EDX;
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_mov_reg_membase (s->code, lreg, lreg,
x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
-
- PRINT_REG ("CALL_I8(INTERFACE)", tree->reg1);
+ X86_CALL_END;
mono_assert (tree->reg1 == X86_EAX);
mono_assert (tree->reg2 == X86_EDX);
stmt: ARG_I8 (lreg) {
+ int pad = tree->data.arg_info.pad;
+
+ X86_ARG_PAD (pad);
x86_push_reg (s->code, tree->left->reg2);
x86_push_reg (s->code, tree->left->reg1);
}
x86_fst80_membase (s->code, X86_ESP, 0);
/* test if lreg is negative */
- x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
+ x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
br [0] = s->code; x86_branch8 (s->code, X86_CC_GEZ, 0, TRUE);
/* add correction constant mn */
x86_fld80_membase (s->code, X86_ESP, 0);
x86_fp_op_reg (s->code, X86_FADD, 1, TRUE);
x86_fst80_membase (s->code, X86_ESP, 0);
-
+ //x86_breakpoint (s->code);
x86_patch (br [0], s->code);
x86_fld80_membase (s->code, X86_ESP, 0);
}
stmt: ARG_R4 (freg) {
- x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
+ int pad = tree->data.arg_info.pad;
+
+ x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4 + pad);
x86_fst_membase (s->code, X86_ESP, 0, FALSE, TRUE);
}
stmt: ARG_R8 (freg) {
- x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
+ int pad = tree->data.arg_info.pad;
+
+ x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8 + pad);
x86_fst_membase (s->code, X86_ESP, 0, TRUE, TRUE);
}
}
}
+freg: CALL_R8 (this, reg) {
+ int treg = X86_EAX;
+ int lreg = tree->left->reg1;
+ int rreg = tree->right->reg1;
+
+ if (lreg == treg || rreg == treg)
+ treg = X86_EDX;
+ if (lreg == treg || rreg == treg)
+ treg = X86_ECX;
+ if (lreg == treg || rreg == treg)
+ mono_assert_not_reached ();
+
+ X86_CALL_BEGIN;
+
+ x86_call_reg (s->code, rreg);
+
+ X86_CALL_END;
+}
+
freg: CALL_R8 (this, ADDR_G) {
int lreg = tree->left->reg1;
int treg = X86_EAX;
if (lreg == treg)
treg = X86_EDX;
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
x86_call_code (s->code, 0);
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+ X86_CALL_END;
}
freg: CALL_R8 (this, INTF_ADDR) {
if (lreg == treg)
treg = X86_EDX;
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_mov_reg_membase (s->code, lreg, lreg,
x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+ X86_CALL_END;
}
freg: CALL_R8 (this, VFUNC_ADDR) {
if (lreg == treg)
treg = X86_EDX;
- if (tree->left->op != MB_TERM_NOP) {
- mono_assert (lreg >= 0);
- x86_push_reg (s->code, lreg);
- }
-
- if (tree->data.ci.vtype_num) {
- int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
- x86_lea_membase (s->code, treg, X86_EBP, offset);
- x86_push_reg (s->code, treg);
- }
+ X86_CALL_BEGIN;
x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
x86_call_virtual (s->code, lreg,
G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
- if (tree->data.ci.args_size)
- x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+ X86_CALL_END;
}
stmt: RET (freg) {
}
}
+freg: SIN (freg) {
+ x86_fsin (s->code);
+}
+
+freg: COS (freg) {
+ x86_fcos (s->code);
+}
+
+freg: SQRT (freg) {
+ x86_fsqrt (s->code);
+}
+
# support for value types
reg: LDIND_OBJ (reg) {
int treg = X86_EAX;
int lreg = tree->left->reg1;
int rreg = tree->right->reg1;
- int offset;
+ int size, offset;
if (lreg == treg)
treg = X86_EDX;
offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) :
tree->data.fi.field->offset;
- x86_push_imm (s->code, mono_class_value_size (tree->data.fi.klass, NULL));
+ size = mono_class_value_size (tree->data.fi.field->type->data.klass, NULL);
+ x86_push_imm (s->code, size);
x86_push_reg (s->code, tree->right->reg1);
x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, offset);
x86_push_reg (s->code, tree->left->reg1);
}
stmt: ARG_OBJ (CONST_I4) {
+ int pad = tree->data.arg_info.pad;
+
+ X86_ARG_PAD (pad);
x86_push_imm (s->code, tree->left->data.i);
}
stmt: ARG_OBJ (reg) {
- int size = tree->data.i;
+ int size = tree->data.arg_info.size;
+ int pad = tree->data.arg_info.pad;
int sa;
- mono_assert (size > 0);
+ if (!size)
+ return;
- sa = size + 3;
- sa &= ~3;
+ sa = size + pad;
/* reserve space for the argument */
x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, sa);
x86_push_reg (s->code, tree->left->reg1);
x86_push_membase (s->code, X86_EBP, 8);
-
mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, MEMCOPY);
x86_call_code (s->code, 0);
x86_patch (br[1], s->code);
x86_patch (br[2], s->code);
}
+
+gpointer
+mono_ldvirtftn (MonoObject *this, int slot)
+{
+ MonoClass *class;
+ MonoMethod *m;
+ gpointer addr;
+ gboolean is_proxy = FALSE;
+ g_assert (this);
+
+ if ((class = this->vtable->klass) == mono_defaults.transparent_proxy_class) {
+ class = ((MonoTransparentProxy *)this)->klass;
+ is_proxy = TRUE;
+ }
+
+
+ g_assert (slot <= class->vtable_size);
+
+ m = class->vtable [slot];
+
+ if (is_proxy) {
+ return mono_jit_create_remoting_trampoline (m);
+ } else {
+ EnterCriticalSection (metadata_section);
+ addr = mono_compile_method (m);
+ LeaveCriticalSection (metadata_section);
+ return addr;
+ }
+}
+
+gpointer
+mono_ldintftn (MonoObject *this, int slot)
+{
+ MonoClass *class;
+ MonoMethod *m;
+ gpointer addr;
+ gboolean is_proxy = FALSE;
+ g_assert (this);
+
+ if ((class = this->vtable->klass) == mono_defaults.transparent_proxy_class) {
+ class = ((MonoTransparentProxy *)this)->klass;
+ is_proxy = TRUE;
+ }
+
+ g_assert (slot < class->interface_count);
+
+ slot = class->interface_offsets [slot];
+
+ m = class->vtable [slot];
+
+ if (is_proxy) {
+ return mono_jit_create_remoting_trampoline (m);
+ } else {
+ EnterCriticalSection (metadata_section);
+ addr = mono_compile_method (m);
+ LeaveCriticalSection (metadata_section);
+ return addr;
+ }
+}
+
+gpointer mono_ldftn (MonoMethod *method)
+{
+ gpointer addr;
+
+ EnterCriticalSection (metadata_section);
+ addr = mono_compile_method (method);
+ LeaveCriticalSection (metadata_section);
+
+ return addr;
+}