New test.
[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                 guint8 *plt_entry = mono_aot_get_plt_entry (code);
47
48                 /* Patch calling code */
49                 if (plt_entry) {
50                         mono_arch_patch_plt_entry (plt_entry, addr);
51                 } else {
52                         MonoJitInfo *ji = 
53                                 mono_jit_info_table_find (mono_domain_get (), code);
54                         MonoJitInfo *target_ji = 
55                                 mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr));
56
57                         if (mono_method_same_domain (ji, target_ji))
58                                 mono_arch_patch_callsite (code, addr);
59                 }
60         }
61
62         return addr;
63 }
64
65 /*
66  * mono_aot_trampoline:
67  *
68  *   This trampoline handles calls made from AOT code. We try to bypass the 
69  * normal JIT compilation logic to avoid loading the metadata for the method.
70  */
71 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
72 gpointer
73 mono_aot_trampoline (gssize *regs, guint8 *code, guint8 *token_info, 
74                                          guint8* tramp)
75 {
76         MonoImage *image;
77         guint32 token;
78         MonoMethod *method = NULL;
79         gpointer addr;
80         gpointer *vtable_slot;
81         gboolean is_got_entry;
82
83         image = *(gpointer*)(gpointer)token_info;
84         token_info += sizeof (gpointer);
85         token = *(guint32*)(gpointer)token_info;
86
87         addr = mono_aot_get_method_from_token (mono_domain_get (), image, token);
88         if (!addr) {
89                 method = mono_get_method (image, token, NULL);
90                 g_assert (method);
91
92                 //printf ("F: %s\n", mono_method_full_name (method, TRUE));
93
94                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
95                         method = mono_marshal_get_synchronized_wrapper (method);
96
97                 addr = mono_compile_method (method);
98                 g_assert (addr);
99         }
100
101         vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
102
103         if (vtable_slot) {
104                 is_got_entry = mono_aot_is_got_entry (code, (guint8*)vtable_slot);
105
106                 if (!is_got_entry) {
107                         if (!method)
108                                 method = mono_get_method (image, token, NULL);
109                         if (method->klass->valuetype)
110                                 addr = mono_arch_get_unbox_trampoline (method, addr);
111                 }
112         } else {
113                 /* This is a normal call through a PLT entry */
114                 guint8 *plt_entry = mono_aot_get_plt_entry (code);
115
116                 g_assert (plt_entry);
117
118                 mono_arch_patch_plt_entry (plt_entry, addr);
119
120                 is_got_entry = FALSE;
121         }
122
123         /*
124          * Since AOT code is only used in the root domain, 
125          * mono_domain_get () != mono_get_root_domain () means the calling method
126          * is AppDomain:InvokeInDomain, so this is the same check as in 
127          * mono_method_same_domain () but without loading the metadata for the method.
128          */
129         if ((is_got_entry && (mono_domain_get () == mono_get_root_domain ())) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
130                 *vtable_slot = addr;
131
132         return addr;
133 }
134
135 /*
136  * mono_aot_plt_trampoline:
137  *
138  *   This trampoline handles calls made from AOT code through the PLT table.
139  */
140 gpointer
141 mono_aot_plt_trampoline (gssize *regs, guint8 *code, guint8 *aot_module, 
142                                                  guint8* tramp)
143 {
144 #ifdef MONO_ARCH_AOT_PLT_OFFSET_REG
145         guint32 plt_info_offset = regs [MONO_ARCH_AOT_PLT_OFFSET_REG];
146 #else
147         guint32 plt_info_offset = -1;
148 #endif
149
150         return mono_aot_plt_resolve (aot_module, plt_info_offset, code);
151 }
152 #endif
153
154 /**
155  * mono_class_init_trampoline:
156  *
157  * This method calls mono_runtime_class_init () to run the static constructor
158  * for the type, then patches the caller code so it is not called again.
159  */
160 void
161 mono_class_init_trampoline (gssize *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
162 {
163         guint8 *plt_entry = mono_aot_get_plt_entry (code);
164
165         mono_runtime_class_init (vtable);
166
167         if (!mono_running_on_valgrind ()) {
168                 if (plt_entry) {
169                         mono_arch_nullify_plt_entry (plt_entry);
170                 } else {
171                         mono_arch_nullify_class_init_trampoline (code, regs);
172                 }
173         }
174 }
175
176 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
177
178 /**
179  * mono_delegate_trampoline:
180  *
181  *   This trampoline handles calls made from the delegate invoke wrapper. It patches
182  * the function address inside the delegate.
183  */
184 gpointer
185 mono_delegate_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp)
186 {
187         gpointer addr;
188
189         addr = mono_compile_method (m);
190         g_assert (addr);
191
192         mono_arch_patch_delegate_trampoline (code, tramp, regs, addr);
193
194         return addr;
195 }
196
197 #endif