/*
- * testjit.c: The mono JIT compiler.
+ * jit.c: The mono JIT compiler.
*
* Author:
* Dietmar Maurer (dietmar@ximian.com)
*/
#include <config.h>
+#if HAVE_BOEHM_GC
+#include <gc/gc.h>
+#endif
#include <glib.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
+#include <mono/metadata/verify.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/loader.h>
#include <mono/metadata/cil-coff.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/class.h>
#include <mono/metadata/object.h>
+#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/opcodes.h>
#include <mono/metadata/mono-endian.h>
#include <mono/metadata/tokentype.h>
};
#undef OPDEF
-#define OPDEF(a,b,c,d,e,f,g,h,i,j) b,
-static char *opcode_names [] = {
-#include "mono/cil/opcode.def"
-};
-#undef OPDEF
-
#define SET_VARINFO(vi,t,k,o,s) do { vi.type=t; vi.kind=k; vi.offset=o; vi.size=s; } while (0)
#define MAKE_CJUMP(name) \
/* Whether to print function call traces */
gboolean mono_jit_trace_calls = FALSE;
+/* Whether to insert in the code profile callbacks */
+gboolean mono_jit_profile = FALSE;
+
/* Force jit to share code between application domains */
gboolean mono_jit_share_code = FALSE;
+/* maximum number of worker threads */
+int mono_worker_threads = 1;
+
MonoDebugHandle *mono_debug_handle = NULL;
GList *mono_debug_methods = NULL;
-gpointer mono_end_of_stack = NULL;
+/* If non-zero, insert a breakpoint when compiling the next method.
+ * If positive, interpret this variable as a counter and decrement
+ * it after setting the breakpoint. */
+int mono_debug_insert_breakpoint = 0;
-MonoJitInfoTable *mono_jit_info_table = NULL;
+/* This is the address of the last breakpoint which was inserted. */
+gchar *mono_debug_last_breakpoint_address = NULL;
+
+gpointer mono_end_of_stack = NULL;
/* last managed frame (used by pinvoke) */
guint32 lmf_thread_id = 0;
+/* used to store a function pointer called after uncatched exceptions */
+guint32 exc_cleanup_id = 0;
+
+/* stores a pointer to async result used by exceptions */
+guint32 async_result_id = 0;
+
MonoJitStats mono_jit_stats;
CRITICAL_SECTION *metadata_section = NULL;
typedef void (*MonoCCtor) (void);
-MonoJitInfoTable *
-mono_jit_info_table_new ()
-{
- return g_array_new (FALSE, FALSE, sizeof (gpointer));
-}
-
-int
-mono_jit_info_table_index (MonoJitInfoTable *table, gpointer addr)
-{
- int left = 0, right = table->len;
-
- while (left < right) {
- int pos = (left + right) / 2;
- MonoJitInfo *ji = g_array_index (table, gpointer, pos);
- gpointer start = ji->code_start;
- gpointer end = start + ji->code_size;
-
- if (addr < start)
- right = pos;
- else if (addr >= end)
- left = pos + 1;
- else
- return pos;
- }
-
- return left;
-}
-
-MonoJitInfo *
-mono_jit_info_table_find (MonoJitInfoTable *table, gpointer addr)
-{
- int left = 0, right = table->len;
-
- while (left < right) {
- int pos = (left + right) / 2;
- MonoJitInfo *ji = g_array_index (table, gpointer, pos);
- gpointer start = ji->code_start;
- gpointer end = start + ji->code_size;
-
- if (addr < start)
- right = pos;
- else if (addr >= end)
- left = pos + 1;
- else
- return ji;
- }
-
- return NULL;
-}
-
-void
-mono_jit_info_table_add (MonoJitInfoTable *table, MonoJitInfo *ji)
-{
- gpointer start = ji->code_start;
- int pos = mono_jit_info_table_index (table, start);
-
- //printf ("TESTADD %d %p\n", pos, ji->code_start);
- g_array_insert_val (table, pos, ji);
-}
-
-/**
- * runtime_class_init:
- * @klass: the class to initialise
- *
- * Initialise the class @klass by calling the class constructor.
- */
-static void
-runtime_class_init (MonoClass *klass)
-{
- MonoCCtor cctor;
- MonoMethod *method;
- int i;
-
- if (mono_debug_handle)
- mono_debug_add_type (mono_debug_handle, klass);
-
- for (i = 0; i < klass->method.count; ++i) {
- method = klass->methods [i];
- if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
- (strcmp (".cctor", method->name) == 0)) {
-
- cctor = arch_compile_method (method);
- if (!cctor && mono_debug_handle)
- return;
- g_assert (cctor != NULL);
- cctor ();
- return;
- }
- }
- /* No class constructor found */
-}
-
static int
map_store_svt_type (int svt)
{
return -1;
}
+/**
+ * map_remote_stind_type:
+ * @type: the type to map
+ *
+ * Translates the MonoType @type into the corresponding remote store opcode
+ * for the code generator.
+ */
+static int
+map_remote_stind_type (MonoType *type)
+{
+ if (type->byref) {
+ return MB_TERM_REMOTE_STIND_REF;
+ }
+
+ switch (type->type) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_BOOLEAN:
+ return MB_TERM_REMOTE_STIND_I1;
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ return MB_TERM_REMOTE_STIND_I2;
+ case MONO_TYPE_I:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ return MB_TERM_REMOTE_STIND_I4;
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_ARRAY:
+ return MB_TERM_REMOTE_STIND_REF;
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ return MB_TERM_REMOTE_STIND_I8;
+ case MONO_TYPE_R4:
+ return MB_TERM_REMOTE_STIND_R4;
+ case MONO_TYPE_R8:
+ return MB_TERM_REMOTE_STIND_R8;
+ case MONO_TYPE_VALUETYPE:
+ if (type->data.klass->enumtype)
+ return map_remote_stind_type (type->data.klass->enum_basetype);
+ else
+ return MB_TERM_REMOTE_STIND_OBJ;
+ default:
+ g_warning ("unknown type %02x", type->type);
+ g_assert_not_reached ();
+ }
+
+ g_assert_not_reached ();
+ return -1;
+}
+
static int
map_starg_type (MonoType *type)
{
}
static int
-map_arg_type (MonoType *type, gboolean pinvoke)
+map_arg_type (MonoType *type)
{
if (type->byref)
return MB_TERM_ARG_I4;
case MONO_TYPE_ARRAY:
return MB_TERM_ARG_I4;
case MONO_TYPE_STRING:
- if (pinvoke)
- return MB_TERM_ARG_STRING;
return MB_TERM_ARG_I4;
case MONO_TYPE_I8:
case MONO_TYPE_U8:
return MB_TERM_ARG_R8;
case MONO_TYPE_VALUETYPE:
if (type->data.klass->enumtype)
- return map_arg_type (type->data.klass->enum_basetype, pinvoke);
+ return map_arg_type (type->data.klass->enum_basetype);
else
return MB_TERM_ARG_OBJ;
default:
}
static MBTree *
-mono_store_tree (MonoFlowGraph *cfg, int slot, MBTree *s, MBTree **dup)
+mono_store_tree (MonoFlowGraph *cfg, int slot, MBTree *s, MBTree **tdup)
{
MonoMemPool *mp = cfg->mp;
MBTree *t;
vnum = mono_allocate_intvar (cfg, slot, s->svt);
if (s->left->op == MB_TERM_ADDR_L && s->left->data.i == vnum) {
- if (dup)
- *dup = ctree_create_dup (mp, s);
+ if (tdup)
+ *tdup = ctree_create_dup (mp, s);
return NULL;
}
// fall through
} else {
- if (dup)
- *dup = ctree_create_dup (mp, s);
+ if (tdup)
+ *tdup = ctree_create_dup (mp, s);
return NULL;
}
- }
+ }
default: {
g_assert (s->svt != VAL_UNKNOWN);
}
}
- if (dup)
- mono_store_tree (cfg, -1, t, dup);
+ if (tdup)
+ mono_store_tree (cfg, -1, t, tdup);
return t;
}
if (cfg->bblocks)
g_free (cfg->bblocks);
-
+
g_array_free (cfg->varinfo, TRUE);
}
-
-static void
-runtime_object_init (MonoObject *obj)
-{
- MonoClass *klass = obj->vtable->klass;
- MonoMethod *method = NULL;
- void (*ctor) (gpointer this);
- int i;
-
- for (i = 0; i < klass->method.count; ++i) {
- if (!strcmp (".ctor", klass->methods [i]->name) &&
- klass->methods [i]->signature->param_count == 0) {
- method = klass->methods [i];
- break;
- }
- }
-
- g_assert (method);
-
- ctor = arch_compile_method (method);
- ctor (obj);
-}
-
static MonoBBlock *
mono_find_final_block (MonoFlowGraph *cfg, guint32 ip, int type)
{
while (ip < end) {
guint32 cli_addr = ip - header->code;
- //printf ("IL%04x OPCODE %s\n", cli_addr, opcode_names [*ip]);
+ //printf ("IL%04x OPCODE %s\n", cli_addr, mono_opcode_names [*ip]);
if (block_end) {
CREATE_BLOCK (cli_addr);
case MonoInlineNone:
++ip;
break;
+ case MonoInlineString:
+ mono_ldstr (mono_domain_get (), method->klass->image, mono_metadata_token_index (read32 (ip + 1)));
+ /* fall through */
case MonoInlineType:
case MonoInlineField:
case MonoInlineMethod:
case MonoInlineTok:
- case MonoInlineString:
case MonoInlineSig:
case MonoShortInlineR:
case MonoInlineI:
return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
}
+#define INLINE_CALLS 1
+
+#ifdef INLINE_CALLS
+static MonoMethod *
+check_inlining (MonoFlowGraph *cfg, MonoMethod *method, gboolean *virtual, MBTree **stack, int n)
+{
+ MonoImage *image = method->klass->image;
+ MonoMethodHeader *header;
+ MonoMethodSignature *csig, *sig = method->signature;
+ MonoMemPool *mp = cfg->mp;
+ MonoMethod *cm;
+ register const unsigned char *ip, *end;
+ static int c = 0;
+ guint32 token;
+ gboolean stop, v = FALSE;
+ MBTree **stack_copy, *t1;
+ int i, anum, arg_used [256];
+
+ for (i = 0; i < 4; i++)
+ arg_used [i] = 0;
+
+ g_assert (method);
+ if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
+ (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
+ (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+ (method->klass->marshalbyref))
+ return NULL;
+
+ header = ((MonoMethodNormal *)method)->header;
+
+ if (!header)
+ return NULL;
+
+ if (header->num_clauses)
+ return NULL;
+
+ ip = header->code;
+ end = ip + header->code_size;
+
+ stop = FALSE;
+
+ while (!stop && ip < end) {
+
+ switch (*ip) {
+ case CEE_LDARG_0:
+ case CEE_LDARG_1:
+ case CEE_LDARG_2:
+ case CEE_LDARG_3: {
+ int an = (*ip) - CEE_LDARG_0;
+ if (arg_used [an])
+ return NULL;
+ arg_used [an] = TRUE;
+ ++ip;
+ break;
+ }
+ case CEE_LDARG_S:
+ ++ip;
+ if (arg_used [*ip])
+ return NULL;
+ arg_used [*ip] = TRUE;
+ ++ip;
+ break;
+ case CEE_LDNULL:
+ case CEE_LDC_I4_M1:
+ case CEE_LDC_I4_0:
+ case CEE_LDC_I4_1:
+ case CEE_LDC_I4_2:
+ case CEE_LDC_I4_3:
+ case CEE_LDC_I4_4:
+ case CEE_LDC_I4_5:
+ case CEE_LDC_I4_6:
+ case CEE_LDC_I4_7:
+ case CEE_LDC_I4_8:
+ ++ip;
+ break;
+ case CEE_LDC_I4_S:
+ ip += 2;
+ break;
+ case CEE_LDC_I4:
+ case CEE_LDC_R4:
+ ip += 5;
+ break;
+ case CEE_LDC_I8:
+ case CEE_LDC_R8:
+ ip += 9;
+ break;
+ case CEE_CALL:
+ stop = TRUE;
+ break;
+ case CEE_CALLVIRT:
+ v = TRUE;
+ stop = TRUE;
+ break;
+ default:
+ return NULL;
+ }
+ }
+
+ if (ip >= end || *ip != CEE_CALL)
+ return NULL;
+
+ ++ip;
+ token = read32 (ip);
+ ip += 4;
+
+ if (ip >= end)
+ return NULL;
+
+ if (!(ip [0] == CEE_RET ||
+ ((ip + 4) < end &&
+ ip [0] == CEE_STLOC_0 &&
+ ip [1] == CEE_BR_S &&
+ ip [2] == 0 &&
+ ip [3] == CEE_LDLOC_0 &&
+ ip [4] == CEE_RET)))
+ return NULL;
+
+ cm = mono_get_method (image, token, NULL);
+ g_assert (cm);
+
+ csig = cm->signature;
+
+ if (cm == method || sig->hasthis != csig->hasthis ||
+ !mono_metadata_type_equal (sig->ret, csig->ret))
+ return NULL;
+
+ if (csig->param_count > n)
+ return NULL;
+
+ if ((cm->flags & METHOD_ATTRIBUTE_FINAL) ||
+ !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
+ v = 0;
+
+ *virtual = v;
+
+ stack_copy = alloca (sizeof (MBTree *) * n);
+ memcpy (stack_copy, stack, sizeof (MBTree *) * n);
+
+ ip = header->code;
+ end = ip + header->code_size;
+
+ //printf ("C %s.%s:%s %d\n", method->klass->name_space, method->klass->name,
+ //method->name, sig->param_count);
+
+ //for (i = 0; i < (sig->param_count + sig->hasthis); i++)
+ //printf ("STACK0 %d %p\n", i, stack [i]);
+
+ stop = FALSE;
+ anum = 0;
+ while (!stop && ip < end) {
+
+ switch (*ip) {
+ case CEE_LDARG_0:
+ case CEE_LDARG_1:
+ case CEE_LDARG_2:
+ case CEE_LDARG_3:
+ stack [anum] = stack_copy [(*ip) - CEE_LDARG_0];
+ //printf ("ARG %d %p\n", anum, stack [anum]);
+ ++ip;
+ break;
+ case CEE_LDARG_S:
+ ++ip;
+ stack [anum] = stack_copy [*ip];
+ //printf ("ARGS %d %p\n", anum, stack [anum]);
+ ++ip;
+ break;
+ case CEE_LDNULL:
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
+ t1->data.i = 0;
+ //printf ("CONST %d %p\n", anum, t1);
+ stack [anum] = t1;
+ ++ip;
+ break;
+ case CEE_LDC_I4_M1:
+ case CEE_LDC_I4_0:
+ case CEE_LDC_I4_1:
+ case CEE_LDC_I4_2:
+ case CEE_LDC_I4_3:
+ case CEE_LDC_I4_4:
+ case CEE_LDC_I4_5:
+ case CEE_LDC_I4_6:
+ case CEE_LDC_I4_7:
+ case CEE_LDC_I4_8:
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
+ t1->data.i = (*ip) - CEE_LDC_I4_0;
+ //printf ("CONST %d %p\n", anum, t1);
+ stack [anum] = t1;
+ ++ip;
+ break;
+ case CEE_LDC_I4_S:
+ ++ip;
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
+ t1->data.i = *(const gint8 *)ip;
+ stack [anum] = t1;
+ ++ip;
+ break;
+ case CEE_LDC_I4:
+ ++ip;
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
+ t1->data.i = read32 (ip);
+ stack [anum] = t1;
+ ip += 4;
+ break;
+ case CEE_LDC_I8:
+ ++ip;
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I8);
+ t1->data.l = read64 (ip);
+ stack [anum] = t1;
+ ip += 8;
+ break;
+ case CEE_LDC_R4: {
+ float *f = mono_alloc_static (sizeof (float));
+ ++ip;
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R4);
+ readr4 (ip, f);
+ t1->data.p = f;
+ stack [anum] = t1;
+ ip += 4;
+ break;
+ }
+ case CEE_LDC_R8: {
+ float *d = mono_alloc_static (sizeof (double));
+ ++ip;
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_R8);
+ readr8 (ip, d);
+ t1->data.p = d;
+ stack [anum] = t1;
+ ip += 8;
+ break;
+ }
+ case CEE_CALL:
+ stop = TRUE;
+ break;
+ case CEE_CALLVIRT:
+ v = TRUE;
+ stop = TRUE;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ anum++;
+ }
+
+ /*
+ for (i = 0; i < (csig->param_count + csig->hasthis); i++)
+ printf ("STACK1 %d %p\n", i, stack [i]);
+
+
+ printf ("C1 %s.%s:%s %d\n", method->klass->name_space, method->klass->name,
+ method->name, c++);
+ */
+
+ return cm;
+
+}
+#endif
+
#define ADD_TREE(t,a) do { t->cli_addr = a; g_ptr_array_add (forest, (t)); } while (0)
#define PUSH_TREE(t,k) do { int tt = k; *sp = t; t->svt = tt; sp++; } while (0)
int varnum = 0, firstarg = 0, retvtarg = 0;
gboolean repeat, superblock_end;
MonoBBlock *bb, *tbb;
+ int maxstack;
header = ((MonoMethodNormal *)method)->header;
signature = method->signature;
image = method->klass->image;
- sp = stack = alloca (sizeof (MBTree *) * (header->max_stack + 1));
+ /* we add 10 extra slots for method inlining */
+ maxstack = header->max_stack + 10;
+ sp = stack = alloca (sizeof (MBTree *) * (maxstack + 1));
if (header->num_locals) {
int size, align;
-
+
for (i = 0; i < header->num_locals; ++i) {
size = mono_type_size (header->locals [i], &align);
varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, VAL_UNKNOWN);
superblock_end = FALSE;
+
while (ip < end) {
guint32 cli_addr = ip - header->code;
- //printf ("%d IL%04x OPCODE %s %d %d %d\n", i, cli_addr, opcode_names [*ip],
+ //printf ("%d IL%04x OPCODE %s %d %d %d\n", i, cli_addr, mono_opcode_names [*ip],
//forest->len, superblock_end, sp - stack);
switch (*ip) {
}
case CEE_LDSTR: {
MonoObject *o;
- guint32 index;
+ guint32 ind;
++ip;
- index = mono_metadata_token_index (read32 (ip));
+ ind = mono_metadata_token_index (read32 (ip));
ip += 4;
if (cfg->share_code) {
t1 = mono_ctree_new_leaf (mp, MB_TERM_LDSTR);
- t1->data.i = index;
+ t1->data.i = ind;
} else {
- o = (MonoObject *) mono_ldstr (cfg->domain, image, index);
+ o = (MonoObject *) mono_ldstr (cfg->domain, image, ind);
t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
t1->data.p = o;
}
field = mono_class_get_field (klass, token);
}
g_assert (field);
-
- t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
- if (klass->valuetype)
- t1->data.i = field->offset - sizeof (MonoObject);
- else
- t1->data.i = field->offset;
+ if (klass->marshalbyref) {
+ t1 = mono_ctree_new (mp, MB_TERM_REMOTE_LDFLDA, sp [0], NULL);
+ t1->data.fi.klass = klass;
+ t1->data.fi.field = field;
+ } else {
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
+
+ if (klass->valuetype)
+ t1->data.i = field->offset - sizeof (MonoObject);
+ else
+ t1->data.i = field->offset;
- t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
+ t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
+ }
- if (!load_addr)
+ if (!load_addr)
t1 = ctree_create_load (cfg, field->type, t1, &svt, FALSE);
else
svt = VAL_POINTER;
}
g_assert (field);
- t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
- if (klass->valuetype)
- t1->data.i = field->offset - sizeof (MonoObject);
- else
- t1->data.i = field->offset;
-
- //printf ("VALUETYPE %d %d %d\n", klass->valuetype, field->offset, t1->data.i);
+ if (klass->marshalbyref) {
+ t1 = mono_ctree_new (mp, map_remote_stind_type (field->type), sp [0], sp [1]);
+ t1->data.fi.klass = klass;
+ t1->data.fi.field = field;
+ } else {
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
+ t1->data.i = klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset;
+ t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
+ t1 = ctree_create_store (cfg, field->type, t1, sp [1], FALSE);
+ }
- t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
- t1 = ctree_create_store (cfg, field->type, t1, sp [1], FALSE);
ADD_TREE (t1, cli_addr);
break;
break;
}
case CEE_SWITCH: {
- guint32 i, n;
+ guint32 k, n;
MonoBBlock **jt;
gint32 st, target;
create_outstack (cfg, bb, stack, sp - stack);
- for (i = 1; i <= (n + 1); i++) {
- if (i > n)
+ for (k = 1; k <= (n + 1); k++) {
+ if (k > n)
target = st;
else {
target = read32 (ip) + st;
g_assert (bcinfo [target].is_block_start);
tbb = &cfg->bblocks [bcinfo [target].block_id];
mark_reached (cfg, tbb, stack, sp - stack);
- jt [i] = tbb;
+ jt [k] = tbb;
}
ADD_TREE (t1, cli_addr);
}
case CEE_NEWOBJ: {
MonoMethodSignature *csig;
- MethodCallInfo *ci;
MonoMethod *cm;
MBTree *this = NULL;
guint32 token;
- int i, align, size, args_size = 0;
+ int k, align, size, args_size = 0;
int newarr = FALSE;
++ip;
g_assert (cm);
g_assert (!strcmp (cm->name, ".ctor"));
- ci = mono_mempool_alloc0 (mp, sizeof (MethodCallInfo));
- ci->m = cm;
-
csig = cm->signature;
g_assert (csig->call_convention == MONO_CALL_DEFAULT);
g_assert (csig->hasthis);
args_size += sizeof (gpointer); /* this argument */
- for (i = csig->param_count - 1; i >= 0; i--) {
- MonoType *type = cm->signature->params [i];
+ for (k = csig->param_count - 1; k >= 0; k--) {
+ MonoType *type = cm->signature->params [k];
size = mono_type_stack_size (type, &align);
- t1 = mono_ctree_new (mp, map_arg_type (type, FALSE), arg_sp [i], NULL);
+ t1 = mono_ctree_new (mp, map_arg_type (type), arg_sp [k], NULL);
t1->data.i = size;
ADD_TREE (t1, cli_addr);
args_size += size;
}
- ci->args_size = args_size;
if (newarr) {
t2->data.p = mono_array_new_va;
t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
- t1->data.p = ci;
+ t1->data.ci.m = cm;
+ t1->data.ci.args_size = args_size;
+ t1->data.ci.vtype_num = 0;
+
t1->svt = VAL_POINTER;
t1 = mono_store_tree (cfg, -1, t1, &t2);
PUSH_TREE (t2, t2->svt);
} else {
-
+
t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
t2->data.p = arch_create_jit_trampoline (cm);
t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), this, t2);
- t1->data.p = ci;
+ t1->data.ci.m = cm;
+ t1->data.ci.args_size = args_size;
+ t1->data.ci.vtype_num = 0;
t1->svt = svt;
- ADD_TREE (t1, cli_addr);
- t1 = ctree_create_dup (mp, this);
+ ADD_TREE (t1, cli_addr);
+ t1 = ctree_create_dup (mp, this);
+
if (cm->klass->valuetype) {
t2 = ctree_create_load (cfg, &cm->klass->byval_arg, t1, &svt, FALSE);
PUSH_TREE (t2, svt);
case CEE_CALL:
case CEE_CALLVIRT: {
MonoMethodSignature *csig;
- MethodCallInfo *ci;
- MonoMethod *cm;
+ MonoMethod *cm, *im;
MBTree *this = NULL;
guint32 token;
- int i, align, size, args_size = 0;
+ int k, align, size, args_size = 0;
int virtual = *ip == CEE_CALLVIRT;
gboolean array_set = FALSE;
gboolean array_get = FALSE;
- gboolean pinvoke = FALSE;
+ /* fixme: compute this value */
+ gboolean shared_to_unshared_call = FALSE;
int nargs, vtype_num = 0;
++ip;
cm = mono_get_method (image, token, NULL);
g_assert (cm);
- ci = mono_mempool_alloc0 (mp, sizeof (MethodCallInfo));
- ci->m = cm;
-
- 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);
- }
+ arg_sp = sp -= cm->signature->param_count;
if ((cm->flags & METHOD_ATTRIBUTE_FINAL) ||
!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
virtual = 0;
+#ifdef INLINE_CALLS
+ if (!virtual) {
+ MBTree **sp1 = sp;
+
+ if (cm->signature->hasthis)
+ sp1--;
+
+ while (!virtual &&
+ (im = check_inlining (cfg, cm, &virtual, sp1, maxstack - (sp1 - stack)))) {
+ cm = im;
+ /*
+ printf ("INLINING %s.%s:%s %s.%s:%s\n", method->klass->name_space,
+ method->klass->name, method->name, cm->klass->name_space,
+ cm->klass->name, cm->name);
+ */
+ }
+ }
+#endif
csig = cm->signature;
+ nargs = csig->param_count;
g_assert (csig->call_convention == MONO_CALL_DEFAULT);
g_assert (!virtual || csig->hasthis);
/* fixme: we need to unbox the this pointer for value types ?*/
g_assert (!virtual || !cm->klass->valuetype);
- nargs = csig->param_count;
- arg_sp = sp -= nargs;
-
+#ifdef INLINE_CALLS
+ if (!virtual && csig->ret->type == MONO_TYPE_VOID &&
+ !(cm->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) &&
+ !(cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
+ !(cm->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
+ !cm->klass->marshalbyref) {
+ MonoMethodHeader *mh = ((MonoMethodNormal *)cm)->header;
+
+ if (mh &&
+ ((mh->code_size == 1 && mh->code [0] == CEE_RET) ||
+ (mh->code_size == 2 && mh->code [0] == CEE_NOP &&
+ mh->code [1] == CEE_RET))) {
+ //static int c = 0;
+
+ if (csig->hasthis)
+ sp--;
+
+ //printf ("C %s.%s:%s %d\n", cm->klass->name_space, cm->klass->name, cm->name, c++);
+ break;
+ }
+ }
+#endif
+
if (cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
if (cm->klass->parent == mono_defaults.array_class) {
if (!strcmp (cm->name, "Set")) {
}
}
- 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);
+ for (k = nargs - 1; k >= 0; k--) {
+ MonoType *type = cm->signature->params [k];
+ t1 = mono_ctree_new (mp, map_arg_type (type), arg_sp [k], NULL);
size = mono_type_stack_size (type, &align);
t1->data.i = size;
ADD_TREE (t1, cli_addr);
this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
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);
}
- ci->args_size = args_size;
- ci->vtype_num = vtype_num;
-
if (array_get) {
- int size, align, vnum;
+ int vnum;
t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
t2->data.p = ves_array_element_address;
t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
- t1->data.p = ci;
-
+ t1->data.ci.m = cm;
+ t1->data.ci.args_size = args_size;
+ t1->data.ci.vtype_num = vtype_num;
+
t1 = mono_ctree_new (mp, map_ldind_type (csig->ret, &svt), t1, NULL);
t1->svt = svt;
t2->data.p = ves_array_element_address;
t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
- t1->data.p = ci;
+ t1->data.ci.m = cm;
+ t1->data.ci.args_size = args_size;
+ t1->data.ci.vtype_num = vtype_num;
t1 = ctree_create_store (cfg, csig->params [nargs], t1, arg_sp [nargs], FALSE);
ADD_TREE (t1, cli_addr);
} else {
- if (virtual) {
+ if (virtual || (csig->hasthis && (cm->klass->marshalbyref ||
+ shared_to_unshared_call ||
+ cm->klass == mono_defaults.object_class))) {
mono_class_init (cm->klass);
if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
t2->data.m = cm;
} else {
-
t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
t2->data.p = arch_create_jit_trampoline (cm);
}
t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), this, t2);
- t1->data.p = ci;
+ t1->data.ci.m = cm;
+ t1->data.ci.args_size = args_size;
+ t1->data.ci.vtype_num = vtype_num;
t1->svt = svt;
if (csig->ret->type != MONO_TYPE_VOID) {
t1 = mono_store_tree (cfg, -1, t1, &t2);
g_assert (t1);
ADD_TREE (t1, cli_addr);
-
- if (pinvoke && csig->ret->type == MONO_TYPE_STRING) {
- t2 = mono_ctree_new (mp, MB_TERM_TOSTRING, t2, NULL);
- t2->svt = VAL_POINTER;
- }
PUSH_TREE (t2, t2->svt);
}
} else
}
- 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: {
--sp;
c = mono_class_get (image, token);
+ if (!c->inited)
+ mono_class_init (c);
t1 = mono_ctree_new (mp, MB_TERM_ISINST, *sp, NULL);
t1->data.klass = c;
--sp;
c = mono_class_get (image, token);
+ if (!c->inited)
+ mono_class_init (c);
t1 = mono_ctree_new (mp, MB_TERM_CASTCLASS, *sp, NULL);
t1->data.klass = c;
case CEE_LDC_I4_S: {
++ip;
t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
- t1->data.i = *(gint8 *)ip;
+ t1->data.i = *(const gint8 *)ip;
++ip;
PUSH_TREE (t1, VAL_I32);
break;
t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
t1->data.i = LOCAL_POS (n);
- t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
+ if (!ISSTRUCT (LOCAL_TYPE (n)))
+ t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
PUSH_TREE (t1, svt);
break;
t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
t1->data.i = LOCAL_POS (*ip);
- t1 = ctree_create_load (cfg, LOCAL_TYPE (*ip), t1, &svt, FALSE);
+ if (!ISSTRUCT (LOCAL_TYPE (*ip)))
+ t1 = ctree_create_load (cfg, LOCAL_TYPE (*ip), t1, &svt, FALSE);
++ip;
PUSH_TREE (t1, svt);
t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
t1->data.i = ARG_POS (n);
- t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
+ if (!ISSTRUCT (ARG_TYPE (n)))
+ t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
+
PUSH_TREE (t1, svt);
break;
}
t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
t1->data.i = ARG_POS (*ip);
- t1 = ctree_create_load (cfg, ARG_TYPE (*ip), t1, &svt, TRUE);
+ if (!ISSTRUCT (ARG_TYPE (*ip)))
+ t1 = ctree_create_load (cfg, ARG_TYPE (*ip), t1, &svt, TRUE);
PUSH_TREE (t1, svt);
++ip;
break;
switch (*ip) {
case CEE_LDLOC: {
+ int n;
++ip;
-
+ n = read16 (ip);
+
t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
- t1->data.i = LOCAL_POS (read16 (ip));
- t1 = ctree_create_load (cfg, LOCAL_TYPE (read16 (ip)), t1, &svt, FALSE);
+ t1->data.i = LOCAL_POS (n);
+ if (!ISSTRUCT (LOCAL_TYPE (n)))
+ t1 = ctree_create_load (cfg, LOCAL_TYPE (n), t1, &svt, FALSE);
ip += 2;
PUSH_TREE (t1, svt);
cm = mono_get_method (image, token, NULL);
g_assert (cm);
- t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
- if (!cm->addr)
- t1->data.p = arch_compile_method (cm);
- else
- t1->data.p = (char *)cm->addr;
+ t1 = mono_ctree_new_leaf (mp, MB_TERM_LDFTN);
+ t1->data.m = cm;
PUSH_TREE (t1, VAL_POINTER);
break;
}
t2->data.m = cm;
- t1 = mono_ctree_new (mp, MB_TERM_LDFTN, *sp, t2);
+ t1 = mono_ctree_new (mp, MB_TERM_LDVIRTFTN, *sp, t2);
PUSH_TREE (t1, VAL_POINTER);
t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
t1->data.i = ARG_POS (n);
- t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
+ if (!ISSTRUCT (ARG_TYPE (n)))
+ t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
PUSH_TREE (t1, svt);
break;
}
}
default:
g_warning ("unknown instruction `%s' at IL_%04X",
- opcode_names [*ip], ip - header->code);
+ mono_opcode_names [*ip], ip - header->code);
if (mono_debug_handle) {
cfg->invalid = 1;
return;
g_assert_not_reached ();
}
-/**
- * mono_jit_assembly:
- * @assembly: reference to an assembly
- *
- * JIT compilation of all methods in the assembly. Prints debugging
- * information on stdout.
- */
-static void
-mono_jit_assembly (MonoAssembly *assembly)
-{
- MonoImage *image = assembly->image;
- MonoMethod *method;
- MonoTableInfo *t = &image->tables [MONO_TABLE_METHOD];
- int i;
-
- for (i = 0; i < t->rows; i++) {
-
- method = mono_get_method (image,
- (MONO_TABLE_METHOD << 24) | (i + 1),
- NULL);
-
- printf ("\nMethod: %s\n\n", method->name);
-
- if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
- printf ("ABSTARCT\n");
- else
- arch_compile_method (method);
-
- }
-
-}
-
-static gint32
-jit_exec_main (MonoMethod *method, MonoArray *args)
-{
- gint32 (*mfunc) (MonoArray*);
- gint32 res;
-
- mfunc = arch_compile_method (method);
-
- res = mfunc (args);
-
- if (method->signature->ret->type == MONO_TYPE_VOID)
- res = 0;
-
- return res;
-}
-
/**
* mono_jit_exec:
* @assembly: reference to an assembly
*
* Start execution of a program.
*/
-static int
+int
mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
{
MonoArray *args = NULL;
args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
for (i = 0; i < argc; ++i) {
MonoString *arg = mono_string_new (domain, argv [i]);
- mono_array_set (args, gpointer, i, mono_string_intern (arg));
+ mono_array_set (args, gpointer, i, arg);
}
}
return mono_runtime_exec_main (method, args);
}
-static void
-usage (char *name)
-{
- fprintf (stderr,
- "%s %s, the Mono ECMA CLI JIT Compiler, (C) 2001 Ximian, Inc.\n\n"
- "Usage is: %s [options] executable args...\n", name, VERSION, name);
- fprintf (stderr,
- "Valid Options are:\n"
- "-d debug the jit, show disassembler output.\n"
- "--dump-asm dumps the assembly code generated\n"
- "--dump-forest dumps the reconstructed forest\n"
- "--trace-calls printf function call trace\n"
- "--share-code force jit to produce shared code\n"
- "--print-vtable print the VTable of all used classes\n"
- "--stabs write stabs debug information\n"
- "--stats print statistics about the jit operations\n"
- "--compile cname compile methods in given class (namespace.name[:methodname])\n"
- "--ncompile num compile methods num times (default: 1000)\n"
- "--debug name insert a breakpoint at the start of method name\n"
- "--help print this help message\n");
- exit (1);
-}
+#ifdef PLATFORM_WIN32
+#define GET_CONTEXT \
+ struct sigcontext *ctx = (struct sigcontext*)_dummy;
+#else
+#define GET_CONTEXT \
+ void **_p = (void **)&_dummy; \
+ struct sigcontext *ctx = (struct sigcontext *)++_p;
+#endif
static void
sigfpe_signal_handler (int _dummy)
{
MonoException *exc;
- void **_p = (void **)&_dummy;
- struct sigcontext *ctx = (struct sigcontext *)++_p;
+ GET_CONTEXT
exc = mono_get_exception_divide_by_zero ();
sigill_signal_handler (int _dummy)
{
MonoException *exc;
- void **_p = (void **)&_dummy;
- struct sigcontext *ctx = (struct sigcontext *)++_p;
+ GET_CONTEXT
exc = mono_get_exception_execution_engine ("SIGILL");
sigsegv_signal_handler (int _dummy)
{
MonoException *exc;
- void **_p = (void **)&_dummy;
- struct sigcontext *ctx = (struct sigcontext *)++_p;
+ GET_CONTEXT
exc = mono_get_exception_null_reference ();
*
* abort the program, print exception information and stack trace
*/
-void
+static void
mono_jit_abort (MonoObject *obj)
{
- char *message = "";
+ const char *message = "";
char *trace = NULL;
MonoString *str; ;
exit (1);
}
-int
-main (int argc, char *argv [])
-{
- MonoDomain *domain;
- struct sigaction sa;
- MonoAssembly *assembly;
- int retval = 0, i;
- int compile_times = 1000;
- char *compile_class = NULL;
- char *file;
- gboolean testjit = FALSE;
- int stack, verbose = FALSE;
- CRITICAL_SECTION ms;
-
- mono_end_of_stack = &stack; /* a pointer to a local variable is always < BP */
-
- if (argc < 2)
- usage (argv [0]);
-
- for (i = 1; i < argc && argv [i][0] == '-'; i++){
- if (strcmp (argv [i], "--help") == 0) {
- usage (argv [0]);
- } else if (strcmp (argv [i], "-d") == 0) {
- testjit = TRUE;
- mono_jit_dump_asm = TRUE;
- mono_jit_dump_forest = TRUE;
- } else if (strcmp (argv [i], "--dump-asm") == 0)
- mono_jit_dump_asm = TRUE;
- else if (strcmp (argv [i], "--dump-forest") == 0)
- mono_jit_dump_forest = TRUE;
- else if (strcmp (argv [i], "--trace-calls") == 0)
- mono_jit_trace_calls = TRUE;
- else if (strcmp (argv [i], "--share-code") == 0)
- mono_jit_share_code = TRUE;
- else if (strcmp (argv [i], "--print-vtable") == 0)
- mono_print_vtable = TRUE;
- else if (strcmp (argv [i], "--debug") == 0) {
- mono_debug_methods = g_list_append (mono_debug_methods, argv [++i]);
- } else if (strcmp (argv [i], "--count") == 0) {
- compile_times = atoi (argv [++i]);
- } else if (strcmp (argv [i], "--compile") == 0) {
- compile_class = argv [++i];
- } else if (strcmp (argv [i], "--ncompile") == 0) {
- compile_times = atoi (argv [++i]);
- } else if (strcmp (argv [i], "--stats") == 0) {
- memset (&mono_jit_stats, 0, sizeof (MonoJitStats));
- mono_jit_stats.enabled = TRUE;
- } else if (strcmp (argv [i], "--stabs") == 0) {
- mono_debug_handle = mono_debug_open_file ("");
- } else if (strcmp (argv [i], "--verbose") == 0) {
- verbose = TRUE;;
- } else
- usage (argv [0]);
- }
-
- file = argv [i];
+static CRITICAL_SECTION ms;
- if (!file)
- usage (argv [0]);
+MonoDomain*
+mono_jit_init (char *file) {
+#ifndef PLATFORM_WIN32
+ struct sigaction sa;
+#endif
+ MonoDomain *domain;
+#ifdef PLATFORM_WIN32
+ win32_seh_init();
+ win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
+ win32_seh_set_handler(SIGILL, sigill_signal_handler);
+ win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
+#else /* !PLATFORM_WIN32 */
/* catch SIGFPE */
sa.sa_handler = sigfpe_signal_handler;
sigemptyset (&sa.sa_mask);
sa.sa_flags = 0;
g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
+#if 1
/* catch SIGSEGV */
sa.sa_handler = sigsegv_signal_handler;
sigemptyset (&sa.sa_mask);
sa.sa_flags = 0;
- //g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
+ g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
+#endif
+#endif /* PLATFORM_WIN32 */
mono_init_icall ();
- mono_add_internal_call ("__array_Set", ves_array_set);
- mono_add_internal_call ("__array_Get", ves_array_get);
- mono_add_internal_call ("__array_Address", ves_array_element_address);
+ mono_add_internal_call ("System.Array::Set", ves_array_set);
+ mono_add_internal_call ("System.Array::Get", ves_array_get);
+ mono_add_internal_call ("System.Array::Address", ves_array_element_address);
metadata_section = &ms;
InitializeCriticalSection (metadata_section);
- mono_jit_info_table = mono_jit_info_table_new ();
-
lmf_thread_id = TlsAlloc ();
TlsSetValue (lmf_thread_id, NULL);
+ exc_cleanup_id = TlsAlloc ();
+ TlsSetValue (exc_cleanup_id, mono_jit_abort);
+ async_result_id = TlsAlloc ();
mono_install_trampoline (arch_create_jit_trampoline);
- mono_install_runtime_class_init (runtime_class_init);
- mono_install_runtime_object_init (runtime_object_init);
- mono_install_runtime_exec_main (jit_exec_main);
+ mono_install_remoting_trampoline (arch_create_remoting_trampoline);
mono_install_handler (arch_get_throw_exception ());
mono_install_runtime_invoke (arch_runtime_invoke);
domain = mono_init (file);
+ mono_runtime_init (domain);
mono_thread_init (domain);
mono_network_init ();
+ mono_delegate_init ();
- assembly = mono_domain_assembly_open (domain, file);
- if (!assembly){
- fprintf (stderr, "Can not open image %s\n", file);
- exit (1);
- }
+ return domain;
+}
- if (testjit) {
- mono_jit_assembly (assembly);
- } else if (compile_class) {
- char *cmethod = strrchr (compile_class, ':');
- char *cname;
- char *code;
- int i, j;
- MonoClass *class;
-
- if (cmethod)
- *cmethod++ = 0;
- cname = strrchr (compile_class, '.');
- if (cname)
- *cname++ = 0;
- else {
- cname = compile_class;
- compile_class = "";
- }
- class = mono_class_from_name (assembly->image, compile_class, cname);
- if (!class)
- g_error ("Cannot find class %s.%s", compile_class, cname);
- mono_class_init (class);
- if (cmethod) {
- MonoMethod *m = NULL;
- for (i = 0; i < class->method.count; ++i) {
- if (strcmp (class->methods [i]->name, cmethod) == 0) {
- m = class->methods [i];
- break;;
- }
- }
- if (!m)
- g_error ("Cannot find method %s.%s:%s", compile_class, cname, cmethod);
- for (j = 0; j < compile_times; ++j) {
- code = arch_compile_method (m);
- g_free (code);
- }
- } else {
- for (j = 0; j < compile_times; ++j) {
- for (i = 0; i < class->method.count; ++i) {
- if (class->methods [i]->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
- continue;
- if (class->methods [i]->flags & METHOD_ATTRIBUTE_ABSTRACT)
- continue;
- if (verbose)
- g_print ("Compiling: %s\n", class->methods [i]->name);
- code = arch_compile_method (class->methods [i]);
- g_free (code);
- }
- }
- }
- } else {
- /*
- * skip the program name from the args.
- */
- ++i;
- retval = mono_jit_exec (domain, assembly, argc - i, argv + i);
- printf ("RESULT: %d\n", retval);
- }
+void
+mono_jit_cleanup (MonoDomain *domain)
+{
+ if (mono_debug_handle)
+ mono_debug_close (mono_debug_handle);
+
+#ifdef PLATFORM_WIN32
+ win32_seh_cleanup();
+#endif
- mono_network_cleanup();
- mono_thread_cleanup();
+ mono_delegate_cleanup ();
+ mono_network_cleanup ();
+ mono_thread_cleanup ();
mono_domain_unload (domain, TRUE);
mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
+
+ g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
+ g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
+ g_print ("Used classes: %ld\n", mono_stats.used_class_count);
+ g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
+ g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
}
DeleteCriticalSection (metadata_section);
- return retval;
}
-
-