2005-11-29 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-trampolines.c
1
2 #include <config.h>
3 #include <glib.h>
4
5 #include <mono/metadata/appdomain.h>
6 #include <mono/metadata/metadata-internals.h>
7 #include <mono/metadata/marshal.h>
8 #include <mono/metadata/tabledefs.h>
9
10 #ifdef HAVE_VALGRIND_MEMCHECK_H
11 #include <valgrind/memcheck.h>
12 #endif
13
14 #include "mini.h"
15
16 /**
17  * mono_magic_trampoline:
18  *
19  *   This trampoline handles calls from JITted code.
20  */
21 gpointer
22 mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp)
23 {
24         gpointer addr;
25         gpointer *vtable_slot;
26
27         addr = mono_compile_method (m);
28         g_assert (addr);
29
30         /* the method was jumped to */
31         if (!code)
32                 return addr;
33
34         vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
35
36         if (vtable_slot) {
37                 if (m->klass->valuetype)
38                         addr = mono_arch_get_unbox_trampoline (m, addr);
39
40                 g_assert (*vtable_slot);
41
42                 if (mono_aot_is_got_entry (code, (guint8*)vtable_slot) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
43                         *vtable_slot = mono_get_addr_from_ftnptr (addr);
44         }
45         else {
46                 /* Patch calling code */
47
48                 MonoJitInfo *ji = 
49                         mono_jit_info_table_find (mono_domain_get (), code);
50                 MonoJitInfo *target_ji = 
51                         mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr));
52
53                 if (mono_method_same_domain (ji, target_ji))
54                         mono_arch_patch_callsite (code, addr);
55         }
56
57         return addr;
58 }
59
60 /*
61  * mono_aot_trampoline:
62  *
63  *   This trampoline handles calls made from AOT code. We try to bypass the 
64  * normal JIT compilation logic to avoid loading the metadata for the method.
65  */
66 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
67 gpointer
68 mono_aot_trampoline (gssize *regs, guint8 *code, guint8 *token_info, 
69                                          guint8* tramp)
70 {
71         MonoImage *image;
72         guint32 token;
73         MonoMethod *method = NULL;
74         gpointer addr;
75         gpointer *vtable_slot;
76         gboolean is_got_entry;
77
78         image = *(gpointer*)(gpointer)token_info;
79         token_info += sizeof (gpointer);
80         token = *(guint32*)(gpointer)token_info;
81
82         addr = mono_aot_get_method_from_token (mono_domain_get (), image, token);
83         if (!addr) {
84                 method = mono_get_method (image, token, NULL);
85                 g_assert (method);
86
87                 //printf ("F: %s\n", mono_method_full_name (method, TRUE));
88
89                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
90                         method = mono_marshal_get_synchronized_wrapper (method);
91
92                 addr = mono_compile_method (method);
93                 g_assert (addr);
94         }
95
96         vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
97         g_assert (vtable_slot);
98
99         is_got_entry = mono_aot_is_got_entry (code, (guint8*)vtable_slot);
100
101         if (!is_got_entry) {
102                 if (!method)
103                         method = mono_get_method (image, token, NULL);
104                 if (method->klass->valuetype)
105                         addr = mono_arch_get_unbox_trampoline (method, addr);
106         }
107
108         /*
109          * Since AOT code is only used in the root domain, 
110          * mono_domain_get () != mono_get_root_domain () means the calling method
111          * is AppDomain:InvokeInDomain, so this is the same check as in 
112          * mono_method_same_domain () but without loading the metadata for the method.
113          */
114         if ((is_got_entry && (mono_domain_get () == mono_get_root_domain ())) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
115                 *vtable_slot = addr;
116
117         return addr;
118 }
119 #endif
120
121 /**
122  * mono_class_init_trampoline:
123  *
124  * This method calls mono_runtime_class_init () to run the static constructor
125  * for the type, then patches the caller code so it is not called again.
126  */
127 void
128 mono_class_init_trampoline (gssize *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
129 {
130         mono_runtime_class_init (vtable);
131
132         if (!mono_running_on_valgrind ())
133                 mono_arch_nullify_class_init_trampoline (code, regs);
134 }
135
136 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
137
138 /**
139  * mono_delegate_trampoline:
140  *
141  *   This trampoline handles calls made from the delegate invoke wrapper. It patches
142  * the function address inside the delegate.
143  */
144 gpointer
145 mono_delegate_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp)
146 {
147         gpointer addr;
148
149         addr = mono_compile_method (m);
150         g_assert (addr);
151
152         mono_arch_patch_delegate_trampoline (code, tramp, regs, addr);
153
154         return addr;
155 }
156
157 #endif