2 * emit-x86.c: Support functions for emitting x86 code
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Miguel de Icaza (miguel@ximian.com)
8 * (C) 2001 Ximian, Inc.
14 #include <mono/metadata/assembly.h>
15 #include <mono/metadata/loader.h>
16 #include <mono/metadata/cil-coff.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/class.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/arch/x86/x86-codegen.h>
28 enter_method (MonoMethod *method, char *ebp)
34 printf ("ENTER: %s.%s::%s\n(", method->klass->name_space,
35 method->klass->name, method->name);
38 if (((int)ebp & 3) != 0) {
39 g_error ("unaligned stack detected (%p)", ebp);
44 if (ISSTRUCT (method->signature->ret)) {
47 g_assert (!method->signature->ret->byref);
49 size = mono_type_stack_size (method->signature->ret, &align);
51 printf ("VALUERET:%p, ", *((gpointer *)ebp));
52 ebp += sizeof (gpointer);
55 if (method->signature->hasthis) {
56 if (method->klass->valuetype) {
57 printf ("value:%p, ", *((gpointer *)ebp));
59 o = *((MonoObject **)ebp);
63 class = o->vtable->klass;
65 if (class == mono_defaults.string_class) {
66 printf ("this:[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
68 printf ("this:%p[%s.%s], ", o, class->name_space, class->name);
71 ebp += sizeof (gpointer);
74 for (i = 0; i < method->signature->param_count; ++i) {
75 MonoType *type = method->signature->params [i];
77 size = mono_type_stack_size (type, &align);
80 printf ("[BYREF:%p], ", *((gpointer *)ebp));
81 } else switch (type->type) {
83 case MONO_TYPE_BOOLEAN:
93 printf ("%d, ", *((int *)(ebp)));
95 case MONO_TYPE_STRING: {
96 MonoString *s = *((MonoString **)ebp);
98 g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
99 printf ("[STRING:%p:%s], ", s, mono_string_to_utf8 (s));
101 printf ("[STRING:null], ");
104 case MONO_TYPE_CLASS:
105 case MONO_TYPE_OBJECT: {
106 o = *((MonoObject **)ebp);
108 class = o->vtable->klass;
110 if (class == mono_defaults.string_class) {
111 printf ("[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
112 } else if (class == mono_defaults.int32_class) {
113 printf ("[INT32:%p:%d], ", o, *(gint32 *)((char *)o + sizeof (MonoObject)));
115 printf ("[%s.%s:%p], ", class->name_space, class->name, o);
117 printf ("%p, ", *((gpointer *)(ebp)));
122 case MONO_TYPE_FNPTR:
123 case MONO_TYPE_ARRAY:
124 case MONO_TYPE_SZARRAY:
125 printf ("%p, ", *((gpointer *)(ebp)));
128 printf ("%lld, ", *((gint64 *)(ebp)));
131 printf ("%f, ", *((float *)(ebp)));
134 printf ("%f, ", *((double *)(ebp)));
136 case MONO_TYPE_VALUETYPE:
138 for (j = 0; j < size; j++)
139 printf ("%02x,", *((guint8*)ebp +j));
146 g_assert (align == 4);
148 ebp = (gpointer)((unsigned)ebp & ~(3));
155 leave_method (MonoMethod *method, int edx, int eax, double test)
159 printf ("LEAVE: %s.%s::%s ", method->klass->name_space,
160 method->klass->name, method->name);
162 switch (method->signature->ret->type) {
165 case MONO_TYPE_BOOLEAN:
167 printf ("TRUE:%d", eax);
181 printf ("EAX=%d", eax);
183 case MONO_TYPE_STRING: {
184 MonoString *s = (MonoString *)eax;
187 g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
188 printf ("[STRING:%p:%s]", s, mono_string_to_utf8 (s));
190 printf ("[STRING:null], ");
193 case MONO_TYPE_OBJECT: {
194 MonoObject *o = (MonoObject *)eax;
197 if (o->vtable->klass == mono_defaults.boolean_class) {
198 printf ("[BOOLEAN:%p:%d]", o, *((guint8 *)o + sizeof (MonoObject)));
199 } else if (o->vtable->klass == mono_defaults.int32_class) {
200 printf ("[INT32:%p:%d]", o, *((gint32 *)((char *)o + sizeof (MonoObject))));
202 printf ("[%s.%s:%p]", o->vtable->klass->name_space, o->vtable->klass->name, o);
204 printf ("[OBJECT:%p]", o);
208 case MONO_TYPE_CLASS:
210 case MONO_TYPE_FNPTR:
211 case MONO_TYPE_ARRAY:
212 case MONO_TYPE_SZARRAY:
213 printf ("EAX=%p", (gpointer)eax);
216 *((gint32 *)&l) = eax;
217 *((gint32 *)&l + 1) = edx;
218 printf ("EAX/EDX=%lld", l);
221 printf ("FP=%f\n", test);
224 printf ("(unknown return type)");
231 * arch_emit_prologue:
232 * @cfg: pointer to status information
234 * Emits the function prolog.
237 arch_emit_prologue (MonoFlowGraph *cfg)
239 MonoMethod *method = cfg->method;
240 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
243 x86_push_reg (cfg->code, X86_EBP);
244 x86_mov_reg_reg (cfg->code, X86_EBP, X86_ESP, 4);
246 if (cfg->locals_size)
247 x86_alu_reg_imm (cfg->code, X86_SUB, X86_ESP, cfg->locals_size);
249 if (mono_regset_reg_used (cfg->rs, X86_EBX))
250 x86_push_reg (cfg->code, X86_EBX);
252 if (mono_regset_reg_used (cfg->rs, X86_EDI))
253 x86_push_reg (cfg->code, X86_EDI);
255 if (mono_regset_reg_used (cfg->rs, X86_ESI))
256 x86_push_reg (cfg->code, X86_ESI);
258 if (mono_jit_trace_calls) {
259 x86_push_reg (cfg->code, X86_EBP);
260 x86_push_imm (cfg->code, cfg->method);
261 x86_mov_reg_imm (cfg->code, X86_EAX, enter_method);
262 x86_call_reg (cfg->code, X86_EAX);
263 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 8);
266 /* initialize local vars */
267 if (header->num_locals) {
269 if (header->init_locals) {
270 int offset = g_array_index (cfg->varinfo, MonoVarInfo,
271 cfg->locals_start_index + header->num_locals - 1).offset;
274 if (size == 1 || size == 2 || size == 4) {
275 x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, size);
283 if (!mono_regset_reg_used (cfg->rs, X86_EDI))
284 x86_push_reg (cfg->code, X86_EDI);
285 x86_lea_membase (cfg->code, X86_EDI, X86_EBP, offset);
286 x86_alu_reg_reg (cfg->code, X86_XOR, X86_EAX, X86_EAX);
287 x86_mov_reg_imm (cfg->code, X86_ECX, i);
289 x86_prefix (cfg->code, X86_REP_PREFIX);
290 x86_stosl (cfg->code);
291 for (i = 0; i < j; i++)
292 x86_stosb (cfg->code);
293 if (!mono_regset_reg_used (cfg->rs, X86_EDI))
294 x86_pop_reg (cfg->code, X86_EDI);
298 x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 2);
299 x86_mov_membase_imm (cfg->code, X86_EBP, offset + 2, 0, 1);
304 /* we always need to initialize object pointers */
306 for (i = 0; i < header->num_locals; ++i) {
307 MonoType *t = header->locals [i];
308 int offset = g_array_index (cfg->varinfo, MonoVarInfo, cfg->locals_start_index + i).offset;
311 x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 4);
316 case MONO_TYPE_STRING:
317 case MONO_TYPE_CLASS:
318 case MONO_TYPE_ARRAY:
319 case MONO_TYPE_SZARRAY:
320 case MONO_TYPE_OBJECT:
321 x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 4);
331 * arch_emit_epilogue:
332 * @cfg: pointer to status information
334 * Emits the function epilog.
337 arch_emit_epilogue (MonoFlowGraph *cfg)
339 if (mono_jit_trace_calls) {
340 x86_fld_reg (cfg->code, 0);
341 x86_alu_reg_imm (cfg->code, X86_SUB, X86_ESP, 8);
342 x86_fst_membase (cfg->code, X86_ESP, 0, TRUE, TRUE);
343 x86_push_reg (cfg->code, X86_EAX);
344 x86_push_reg (cfg->code, X86_EDX);
345 x86_push_imm (cfg->code, cfg->method);
346 x86_mov_reg_imm (cfg->code, X86_EAX, leave_method);
347 x86_call_reg (cfg->code, X86_EAX);
348 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 4);
349 x86_pop_reg (cfg->code, X86_EDX);
350 x86_pop_reg (cfg->code, X86_EAX);
351 x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 8);
354 if (mono_regset_reg_used (cfg->rs, X86_ESI))
355 x86_pop_reg (cfg->code, X86_ESI);
357 if (mono_regset_reg_used (cfg->rs, X86_EDI))
358 x86_pop_reg (cfg->code, X86_EDI);
360 if (mono_regset_reg_used (cfg->rs, X86_EBX))
361 x86_pop_reg (cfg->code, X86_EBX);
363 x86_leave (cfg->code);
368 mono_label_cfg (MonoFlowGraph *cfg)
372 for (i = 0; i < cfg->block_count; i++) {
373 GPtrArray *forest = cfg->bblocks [i].forest;
376 if (!cfg->bblocks [i].reached) /* unreachable code */
381 for (j = 0; j < top; j++) {
382 MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
385 mbstate = mono_burg_label (t1, cfg);
388 if (mono_debug_handle)
390 g_warning ("tree does not match");
391 mono_print_ctree (t1); printf ("\n\n");
393 mono_print_forest (forest);
394 g_assert_not_reached ();
401 tree_preallocate_regs (MBTree *tree, int goal, MonoRegSet *rs)
404 case MB_TERM_CALL_I4:
405 case MB_TERM_CALL_I8:
406 case MB_TERM_CALL_R8:
407 // case MB_TERM_CALL_VOID :
408 tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, tree->exclude_mask);
409 tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, tree->exclude_mask);
410 tree->reg3 = mono_regset_alloc_reg (rs, X86_ECX, tree->exclude_mask);
417 case MB_NTERM_lreg: {
422 tree->exclude_mask |= (1 << X86_ECX);
423 tree->left->exclude_mask |= (1 << X86_ECX);
426 case MB_TERM_MUL_OVF:
427 case MB_TERM_MUL_OVF_UN:
432 tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, tree->exclude_mask);
433 tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, tree->exclude_mask);
434 if (goal == MB_NTERM_reg) {
435 tree->left->exclude_mask |= (1 << X86_EDX);
436 tree->right->exclude_mask |= (1 << X86_EDX) | (1 << X86_EAX);
450 tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs)
453 int ern = mono_burg_rule (tree->state, goal);
454 const guint16 *nts = mono_burg_nts [ern];
457 mono_burg_kids (tree, ern, kids);
459 //printf ("RALLOC START %d %p %d\n", tree->op, rs->free_mask, goal);
461 if (nts [0] && kids [0] == tree) {
463 tree_allocate_regs (kids [0], nts [0], rs);
467 for (i = 0; nts [i]; i++)
468 tree_preallocate_regs (kids [i], nts [i], rs);
470 for (i = 0; nts [i]; i++)
471 tree_allocate_regs (kids [i], nts [i], rs);
473 for (i = 0; nts [i]; i++) {
474 mono_regset_free_reg (rs, kids [i]->reg1);
475 mono_regset_free_reg (rs, kids [i]->reg2);
476 mono_regset_free_reg (rs, kids [i]->reg3);
481 if (tree->reg1 < 0) {
482 tree->reg1 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
483 g_assert (tree->reg1 != -1);
488 if (tree->reg1 < 0) {
489 tree->reg1 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
490 g_assert (tree->reg1 != -1);
492 if (tree->reg2 < 0) {
493 tree->reg2 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
494 g_assert (tree->reg2 != -1);
499 /* fixme: allocate floating point registers */
503 if (tree->op == MB_TERM_ADD) {
504 tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
505 tree->reg2 = mono_regset_alloc_reg (rs, tree->right->reg1, tree->exclude_mask);
510 if (tree->op == MB_TERM_ADD) {
511 tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
516 if (tree->op == MB_TERM_SHL ||
517 tree->op == MB_TERM_MUL) {
518 tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
526 //printf ("RALLOC END %d %p\n", tree->op, rs->free_mask);
527 tree->emit = mono_burg_func [ern];
531 arch_allocate_regs (MonoFlowGraph *cfg)
535 for (i = 0; i < cfg->block_count; i++) {
536 GPtrArray *forest = cfg->bblocks [i].forest;
539 if (!cfg->bblocks [i].reached) /* unreachable code */
544 for (j = 0; j < top; j++) {
545 MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
546 //printf ("AREGSTART %d:%d %p\n", i, j, cfg->rs->free_mask);
547 tree_allocate_regs (t1, 1, cfg->rs);
548 //printf ("AREGENDT %d:%d %p\n", i, j, cfg->rs->free_mask);
549 g_assert (cfg->rs->free_mask == 0xffffffff);
555 tree_emit (int goal, MonoFlowGraph *cfg, MBTree *tree)
558 int i, ern = mono_burg_rule (tree->state, goal);
559 const guint16 *nts = mono_burg_nts [ern];
563 mono_burg_kids (tree, ern, kids);
565 for (i = 0; nts [i]; i++)
566 tree_emit (nts [i], cfg, kids [i]);
568 tree->addr = offset = cfg->code - cfg->start;
570 // we assume an instruction uses a maximum of 128 bytes
571 if ((cfg->code_size - offset) <= 128) {
572 int add = MIN (cfg->code_size, 128);
573 cfg->code_size += add;
574 mono_jit_stats.code_reallocs++;
575 cfg->start = g_realloc (cfg->start, cfg->code_size);
576 g_assert (cfg->start);
577 cfg->code = cfg->start + offset;
580 if ((emit = mono_burg_func [ern]))
583 g_assert ((cfg->code - cfg->start) < cfg->code_size);
587 mono_emit_cfg (MonoFlowGraph *cfg)
591 for (i = 0; i < cfg->block_count; i++) {
592 MonoBBlock *bb = &cfg->bblocks [i];
593 GPtrArray *forest = bb->forest;
596 if (!bb->reached) /* unreachable code */
601 bb->addr = cfg->code - cfg->start;
603 for (j = 0; j < top; j++) {
604 MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
606 tree_emit (1, cfg, t1);
610 cfg->epilog = cfg->code - cfg->start;
614 mono_compute_branches (MonoFlowGraph *cfg)
622 for (j = 0; j < cfg->block_count; j++) {
623 MonoBBlock *bb = &cfg->bblocks [j];
624 GPtrArray *forest = bb->forest;
627 if (!bb->reached) /* unreachable code */
632 for (i = 0; i < top; i++) {
633 MBTree *t1 = (MBTree *) g_ptr_array_index (forest, i);
635 if (t1->op == MB_TERM_SWITCH) {
636 MonoBBlock **jt = (MonoBBlock **)t1->data.p;
637 guint32 *rt = (guint32 *)t1->data.p;
638 int m = *((guint32 *)t1->data.p) + 1;
641 for (k = 1; k <= m; k++)
642 rt [k] = (int)(jt [k]->addr + cfg->start);
644 /* emit the switch instruction again to update addresses */
645 cfg->code = cfg->start + t1->addr;
646 ((MBEmitFunc)t1->emit) (t1, cfg);
653 for (ji = cfg->jump_info; ji; ji = ji->next) {
654 gpointer *ip = GUINT_TO_POINTER (GPOINTER_TO_UINT (ji->ip) + cfg->start);
658 case MONO_JUMP_INFO_BB:
659 target = ji->data.bb->addr + cfg->start;
660 *ip = target - GPOINTER_TO_UINT(ip) - 4;
662 case MONO_JUMP_INFO_ABS:
663 target = ji->data.target;
664 *ip = target - GPOINTER_TO_UINT(ip) - 4;
666 case MONO_JUMP_INFO_EPILOG:
667 target = cfg->epilog + cfg->start;
668 *ip = target - GPOINTER_TO_UINT(ip) - 4;
670 case MONO_JUMP_INFO_IP:
674 g_assert_not_reached ();
680 mono_add_jump_info (MonoFlowGraph *cfg, gpointer ip, MonoJumpInfoType type, gpointer target)
682 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mp, sizeof (MonoJumpInfo));
685 ji->ip = GUINT_TO_POINTER (GPOINTER_TO_UINT (ip) - GPOINTER_TO_UINT (cfg->start));
686 ji->data.target = target;
687 ji->next = cfg->jump_info;
693 match_debug_method (MonoMethod* method)
695 GList *tmp = mono_debug_methods;
697 for (; tmp; tmp = tmp->next) {
698 if (mono_method_desc_full_match (tmp->data, method))
705 * arch_compile_method:
706 * @method: pointer to the method info
708 * JIT compilation of a single method.
710 * Returns: a pointer to the newly created code.
713 arch_compile_method (MonoMethod *method)
715 MonoDomain *target_domain, *domain = mono_domain_get ();
718 GHashTable *jit_code_hash;
720 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
721 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
723 method->info = arch_create_native_wrapper (method);
727 if (mono_jit_share_code)
728 target_domain = mono_root_domain;
730 target_domain = domain;
732 jit_code_hash = target_domain->jit_code_hash;
734 if ((addr = g_hash_table_lookup (jit_code_hash, method))) {
735 mono_jit_stats.methods_lookups++;
739 mono_jit_stats.methods_compiled++;
741 if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
742 printf ("Start JIT compilation of %s.%s:%s\n", method->klass->name_space,
743 method->klass->name, method->name);
746 if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
747 const char *name = method->name;
749 gboolean delegate = FALSE;
751 if (method->klass->parent == mono_defaults.multicastdelegate_class)
754 if (delegate && *name == '.' && (strcmp (name, ".ctor") == 0)) {
755 addr = (gpointer)mono_delegate_ctor;
756 } else if (delegate && *name == 'I' && (strcmp (name, "Invoke") == 0)) {
759 addr = arch_get_delegate_invoke (method, &size);
761 if (mono_jit_dump_asm) {
762 char *id = g_strdup_printf ("%s.%s_%s", method->klass->name_space,
763 method->klass->name, method->name);
764 mono_disassemble_code (addr, size, id);
767 } else if (delegate && *name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
768 code = addr = g_malloc (32);
769 x86_push_imm (code, method);
770 x86_call_code (code, arch_begin_invoke);
771 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
773 g_assert ((code - addr) <= 32);
774 } else if (delegate && *name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
775 /* this can raise exceptions, so we need a wrapper to save/restore LMF */
776 method->addr = (gpointer)arch_end_invoke;
777 addr = arch_create_native_wrapper (method);
779 if (mono_debug_handle)
782 g_error ("Don't know how to exec runtime method %s.%s::%s",
783 method->klass->name_space, method->klass->name, method->name);
787 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
790 gulong code_size_ratio;
792 ji = mono_mempool_alloc0 (target_domain->mp, sizeof (MonoJitInfo));
794 mp = mono_mempool_new ();
796 cfg = mono_cfg_new (method, mp);
798 mono_analyze_flow (cfg);
802 mono_analyze_stack (cfg);
806 cfg->rs = mono_regset_new (X86_NREG);
807 mono_regset_reserve_reg (cfg->rs, X86_ESP);
808 mono_regset_reserve_reg (cfg->rs, X86_EBP);
810 cfg->code_size = MAX (header->code_size * 5, 256);
811 cfg->start = cfg->code = g_malloc (cfg->code_size);
813 mono_debug_last_breakpoint_address = cfg->code;
815 if (match_debug_method (method) || mono_debug_insert_breakpoint)
816 x86_breakpoint (cfg->code);
817 else if (mono_debug_handle)
820 if (mono_debug_insert_breakpoint > 0)
821 mono_debug_insert_breakpoint--;
823 if (mono_jit_dump_forest) {
825 printf ("FOREST %s.%s:%s\n", method->klass->name_space,
826 method->klass->name, method->name);
827 for (i = 0; i < cfg->block_count; i++) {
828 printf ("BLOCK %d:\n", i);
829 mono_print_forest (cfg->bblocks [i].forest);
833 mono_label_cfg (cfg);
837 arch_allocate_regs (cfg);
839 /* align to 8 byte boundary */
840 cfg->locals_size += 7;
841 cfg->locals_size &= ~7;
843 arch_emit_prologue (cfg);
844 cfg->prologue_end = cfg->code - cfg->start;
846 cfg->epilogue_begin = cfg->code - cfg->start;
847 arch_emit_epilogue (cfg);
851 mono_jit_stats.allocated_code_size += cfg->code_size;
853 code_size_ratio = cfg->code - cfg->start;
854 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
855 mono_jit_stats.biggest_method_size = code_size_ratio;
856 mono_jit_stats.biggest_method = method;
858 code_size_ratio = (code_size_ratio * 100) / header->code_size;
859 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
860 mono_jit_stats.max_code_size_ratio = code_size_ratio;
861 mono_jit_stats.max_ratio_method = method;
864 mono_compute_branches (cfg);
866 if (mono_jit_dump_asm) {
867 char *id = g_strdup_printf ("%s.%s_%s", method->klass->name_space,
868 method->klass->name, method->name);
869 mono_disassemble_code (cfg->start, cfg->code - cfg->start, id);
872 if (mono_debug_handle)
873 mono_debug_add_method (mono_debug_handle, cfg);
875 ji->code_size = cfg->code - cfg->start;
876 ji->used_regs = cfg->rs->used_mask;
878 ji->code_start = addr;
880 mono_jit_stats.native_code_size += ji->code_size;
882 if (header->num_clauses) {
883 int i, start_block, end_block;
885 ji->num_clauses = header->num_clauses;
886 ji->clauses = mono_mempool_alloc0 (target_domain->mp,
887 sizeof (MonoJitExceptionInfo) * header->num_clauses);
889 for (i = 0; i < header->num_clauses; i++) {
890 MonoExceptionClause *ec = &header->clauses [i];
891 MonoJitExceptionInfo *ei = &ji->clauses [i];
893 ei->flags = ec->flags;
894 ei->token_or_filter = ec->token_or_filter;
896 g_assert (cfg->bcinfo [ec->try_offset].is_block_start);
897 start_block = cfg->bcinfo [ec->try_offset].block_id;
898 end_block = cfg->bcinfo [ec->try_offset + ec->try_len].block_id;
899 g_assert (cfg->bcinfo [ec->try_offset + ec->try_len].is_block_start);
901 ei->try_start = cfg->start + cfg->bblocks [start_block].addr;
902 ei->try_end = cfg->start + cfg->bblocks [end_block].addr;
904 g_assert (cfg->bcinfo [ec->handler_offset].is_block_start);
905 start_block = cfg->bcinfo [ec->handler_offset].block_id;
906 ei->handler_start = cfg->start + cfg->bblocks [start_block].addr;
908 //printf ("TEST %x %x %x\n", ei->try_start, ei->try_end, ei->handler_start);
912 mono_jit_info_table_add (target_domain, ji);
914 mono_regset_free (cfg->rs);
918 mono_mempool_destroy (mp);
922 if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
923 printf ("END JIT compilation of %s.%s:%s %p %p\n", method->klass->name_space,
924 method->klass->name, method->name, method, addr);
927 g_hash_table_insert (jit_code_hash, method, addr);