if we're intentionally using power-of-two sizing for chunks, don't add the header...
[mono-project/dkf.git] / mono / mini / tramp-hppa.c
blob3054e8c7c61ebf16da24aa8704cd15814dc7198b
1 /*
2 * tramp-hppa.c: JIT trampoline code for hppa
4 * Copyright (c) 2007 Randolph Chung
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
26 #include <config.h>
27 #include <glib.h>
29 #include <mono/arch/hppa/hppa-codegen.h>
30 #include <mono/metadata/appdomain.h>
31 #include <mono/metadata/marshal.h>
32 #include <mono/metadata/tabledefs.h>
34 #include "mini.h"
35 #include "mini-hppa.h"
37 /* sizeof (MonoLMF) == 320 + HPPA_STACK_LMF_OFFSET + linkage area (64 bytes)
38 * leave some room to spare
40 #define TRAMP_STACK_SIZE 512
41 /* Method-specific trampoline code fragment size */
42 #define METHOD_TRAMPOLINE_SIZE 128
43 /* Jump-specific trampoline code fragment size */
44 #define JUMP_TRAMPOLINE_SIZE 64
47 * mono_arch_get_unbox_trampoline:
48 * @gsctx: the generic sharing context
49 * @m: method pointer
50 * @addr: pointer to native code for @m
52 * when value type methods are called through the vtable we need to unbox the
53 * this argument. This method returns a pointer to a trampoline which does
54 * unboxing before calling the method
56 gpointer
57 mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer addr)
59 guint8 *code, *start;
60 int this_pos = hppa_r26;
61 MonoDomain *domain = mono_domain_get ();
63 if (MONO_TYPE_ISSTRUCT (mono_method_signature (m)->ret))
64 this_pos = hppa_r25;
66 start = code = mono_domain_code_reserve (domain, 20);
68 hppa_set (code, addr, hppa_r1);
69 hppa_ldo (code, sizeof (MonoObject), this_pos, this_pos);
70 hppa_bv (code, hppa_r0, hppa_r1);
71 hppa_nop (code);
73 mono_arch_flush_icache (start, code - start);
74 g_assert ((code - start) <= 20);
75 return start;
78 void
79 mono_arch_patch_callsite (guint8 *method_start, guint8 *p, guint8 *addr)
81 guint32 *code = (void *)p;
82 /* Search for and patch the calling sequence
84 * Possibilities are:
86 * CEE_CALL outputs the following sequence:
88 * ldil L'<addr>, r1
89 * ldo R'<addr>, r1
90 * bb,>=,n r1, 30, .+16
91 * depwi 0, 31, 2, r1
92 * ldw 4(r1), r19
93 * ldw 0(r1), r1
94 * ble 0(sr4,r1)
95 * copy r31, rp
96 * XXXXXXXXXXXXXXXX <- code points here
99 /* Go back to the branching insn */
101 code -= 2;
102 /* We can patch the code only if it is a direct call. In some cases
103 * we can reach here via a reg-indirect call. In that case we can't
104 * patch the callsite
106 if ((code[0] >> 26) == 0x39 && /* ble */
107 (code[-4] >> 26) == 0x31 && /* bb */
108 (code[-6] >> 26) == 0x08) /* ldil */ {
109 hppa_patch (&code[-6], addr);
110 mono_arch_flush_icache (&code[-6], 8);
111 } else {
112 printf("Can't patch callsite!\n");
116 void
117 mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
119 g_assert_not_reached ();
122 void
123 mono_arch_nullify_class_init_trampoline (guint8 *code8, mgreg_t *regs)
125 guint32 *buf = (guint32 *)((unsigned long)code8 & ~3);
126 guint32 *code = buf;
128 code -= 2;
129 if (code[0] == 0x08000240) /* nop - already nullified */
130 return;
131 g_assert ((code[0] >> 26) == 0x39); /* ble */
132 hppa_nop (code);
133 hppa_nop (code);
135 mono_arch_flush_icache (buf, 8);
139 void
140 mono_arch_nullify_plt_entry (guint8 *code, mgreg_t *regs)
142 g_assert_not_reached ();
145 #define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
148 * Stack frame description when the generic trampoline is called.
149 * caller frame
150 * --------------------
151 * MonoLMF
152 * -------------------
153 * incoming argument registers
154 * -------------------
155 * linkage area
156 * -------------------
158 guchar*
159 mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
161 guint8 *buf, *code = NULL;
162 int i, offset;
164 code = buf = mono_global_codeman_reserve (1024);
166 /* Trampoline is called with "method" in r20 */
167 hppa_stw (buf, hppa_r2, -20, hppa_sp);
168 hppa_copy (buf, hppa_sp, hppa_r1);
169 hppa_ldo (buf, TRAMP_STACK_SIZE, hppa_sp, hppa_sp);
171 /* Save the MonoLMF structure on the stack */
172 offset = HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, regs);
173 for (i = 0; i < 32; i++) {
174 if (HPPA_IS_SAVED_GREG (i)) {
175 hppa_stw (buf, i, offset, hppa_r1);
176 offset += sizeof(ulong);
179 hppa_copy (buf, hppa_r1, hppa_r3);
180 hppa_set (buf, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, fregs), hppa_r1);
181 for (i = 0; i < 32; i++) {
182 if (HPPA_IS_SAVED_FREG (i)) {
183 hppa_fstdx (buf, i, hppa_r1, hppa_r3);
184 hppa_ldo (buf, sizeof(double), hppa_r1, hppa_r1);
187 /* Save the method info stored in r20 */
188 hppa_stw (buf, hppa_r20, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, method), hppa_r3);
189 hppa_stw (buf, hppa_r3, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, ebp), hppa_sp);
190 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
191 hppa_stw (buf, hppa_r0, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, eip), hppa_r3);
192 } else {
193 hppa_stw (buf, hppa_r2, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, eip), hppa_r3);
196 /* Save the incoming arguments too, before they can trashed by the
197 * call to the magic trampoline
199 offset = HPPA_STACK_LMF_OFFSET + sizeof (MonoLMF);
200 for (i = hppa_r23; i <= hppa_r26; i++) {
201 hppa_stw (buf, i, offset, hppa_r3);
202 offset += sizeof(ulong);
204 hppa_stw (buf, hppa_r28, offset, hppa_r3);
205 offset += sizeof(ulong);
206 offset = ALIGN_TO (offset, sizeof(double));
207 hppa_ldo (buf, offset, hppa_r3, hppa_r1);
208 for (i = hppa_fr4; i <= hppa_fr7; i++) {
209 hppa_fstds (buf, i, 0, hppa_r1);
210 hppa_ldo (buf, sizeof(double), hppa_r1, hppa_r1);
213 /* Call mono_get_lmf_addr */
214 hppa_set (buf, mono_get_lmf_addr, hppa_r1);
215 hppa_depi (buf, 0, 31, 2, hppa_r1);
216 hppa_ldw (buf, 0, hppa_r1, hppa_r1);
217 hppa_ble (buf, 0, hppa_r1);
218 hppa_copy (buf, hppa_r31, hppa_r2);
220 /* r28 now points at the (MonoLMF **) for the current thread. */
222 /* new_lmf->lmf_addr = lmf_addr */
223 hppa_stw (buf, hppa_r28, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, lmf_addr), hppa_r3);
225 /* new_lmf->previous_lmf = *lmf_addr */
226 hppa_ldw (buf, 0, hppa_r28, hppa_r1);
227 hppa_stw (buf, hppa_r1, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, previous_lmf), hppa_r3);
228 /* *lmf_addr = new_lmf */
229 hppa_ldo (buf, HPPA_STACK_LMF_OFFSET, hppa_r3, hppa_r1);
230 hppa_stw (buf, hppa_r1, 0, hppa_r28);
232 /* Call mono_magic_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tramp) */
233 hppa_ldo (buf, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, regs), hppa_r3, hppa_r26);
234 hppa_ldw (buf, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, method), hppa_r3, hppa_r24);
235 if (tramp_type == MONO_TRAMPOLINE_JUMP)
236 hppa_copy (buf, hppa_r0, hppa_r25);
237 else {
238 hppa_ldw (buf, -20, hppa_r3, hppa_r25);
239 /* clear the lower two (privilege) bits */
240 hppa_depi (buf, 0, 31, 2, hppa_r25);
242 hppa_copy (buf, hppa_r0, hppa_r23);
244 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
245 hppa_set (buf, mono_class_init_trampoline, hppa_r1);
246 else
247 hppa_set (buf, mono_magic_trampoline, hppa_r1);
249 hppa_depi (buf, 0, 31, 2, hppa_r1);
250 hppa_ldw (buf, 0, hppa_r1, hppa_r1);
251 hppa_ble (buf, 0, hppa_r1);
252 hppa_copy (buf, hppa_r31, hppa_r2);
254 /* Code address is now in r28 */
256 /* Unwind LMF */
257 hppa_ldw (buf, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, previous_lmf), hppa_r3, hppa_r20);
258 hppa_ldw (buf, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, lmf_addr), hppa_r3, hppa_r21);
259 hppa_stw (buf, hppa_r20, 0, hppa_r21);
261 hppa_copy (buf, hppa_r28, hppa_r20);
263 /* Restore arguments */
264 offset = HPPA_STACK_LMF_OFFSET + sizeof (MonoLMF);
265 for (i = hppa_r23; i <= hppa_r26; i++) {
266 hppa_ldw (buf, offset, hppa_r3, i);
267 offset += sizeof(ulong);
269 hppa_ldw (buf, offset, hppa_r3, hppa_r28);
270 offset += sizeof(ulong);
271 offset = ALIGN_TO (offset, sizeof(double));
272 hppa_ldo (buf, offset, hppa_r3, hppa_r1);
273 for (i = hppa_fr4; i <= hppa_fr7; i++) {
274 hppa_fldds (buf, 0, hppa_r1, i);
275 hppa_ldo (buf, sizeof(double), hppa_r1, hppa_r1);
278 /* Restore registers */
279 hppa_set (buf, HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, fregs), hppa_r1);
280 for (i = 0; i < 32; i++) {
281 if (HPPA_IS_SAVED_FREG (i)) {
282 hppa_flddx (buf, hppa_r1, hppa_r3, i);
283 hppa_ldo (buf, sizeof(double), hppa_r1, hppa_r1);
287 hppa_copy (buf, hppa_r3, hppa_r1);
288 offset = HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, regs);
289 for (i = 0; i < 32; i++) {
290 if (HPPA_IS_SAVED_GREG (i)) {
291 hppa_ldw (buf, offset, hppa_r1, i);
292 offset += sizeof(ulong);
295 /* Jump to the compiled code in hppa_r28 */
296 hppa_ldw (buf, -20, hppa_r1, hppa_r2);
297 hppa_bv (buf, hppa_r0, hppa_r20);
298 hppa_ldo (buf, -TRAMP_STACK_SIZE, hppa_sp, hppa_sp);
300 g_assert ((buf - code) <= 1024);
301 return code;
305 * mono_arch_create_class_init_trampoline:
306 * @vtable: the type to initialize
308 * Creates a trampoline function to run a type initializer.
309 * If the trampoline is called, it calls mono_runtime_class_init with the
310 * given vtable, then patches the caller code so it does not get called any
311 * more.
313 * Returns: a pointer to the newly created code
315 gpointer
316 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
318 guint8 *code, *buf, *tramp;
319 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
320 /* This is the method-specific part of the trampoline. Its purpose is
321 to provide the generic part with the MonoMethod *method pointer. */
322 code = buf = mono_domain_code_reserve (vtable->domain, METHOD_TRAMPOLINE_SIZE);
324 hppa_stw (buf, hppa_r2, -20, hppa_sp);
325 hppa_copy (buf, hppa_r3, hppa_r1);
326 hppa_copy (buf, hppa_sp, hppa_r3);
327 hppa_stwm (buf, hppa_r1, 64, hppa_sp);
329 /* mono_class_init_trampoline (regs, code, vtable, tramp) */
330 hppa_copy (buf, hppa_r0, hppa_r26);
331 hppa_copy (buf, hppa_r2, hppa_r25);
332 hppa_set (buf, vtable, hppa_r24);
333 hppa_copy (buf, hppa_r0, hppa_r23);
335 hppa_set (buf, mono_class_init_trampoline, hppa_r1);
336 hppa_depi (buf, 0, 31, 2, hppa_r1);
337 hppa_ldw (buf, 0, hppa_r1, hppa_r1);
338 hppa_ble (buf, 0, hppa_r1);
339 hppa_copy (buf, hppa_r31, hppa_r2);
341 hppa_ldw (buf, -20, hppa_r3, hppa_r2);
342 hppa_ldo (buf, 64, hppa_r3, hppa_sp);
343 hppa_bv (buf, hppa_r0, hppa_r2);
344 hppa_ldwm (buf, -64, hppa_sp, hppa_r3);
346 /* Flush instruction cache, since we've generated code */
347 mono_arch_flush_icache (code, buf - code);
349 /* Sanity check */
350 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
352 return code;
355 static MonoJitInfo*
356 create_specific_tramp (MonoMethod *method, guint8* tramp, MonoDomain *domain)
358 guint8 *code, *buf;
359 MonoJitInfo *ji;
361 code = buf = mono_domain_code_reserve (domain, 20);
363 /* Call trampoline, with the "method" pointer in r20 */
364 hppa_set (buf, tramp, hppa_r1);
365 hppa_ldil (buf, hppa_lsel (method), hppa_r20);
366 hppa_bv (buf, hppa_r0, hppa_r1);
367 hppa_ldo (buf, hppa_rsel (method), hppa_r20, hppa_r20);
369 /* Flush instruction cache, since we've generated code */
370 mono_arch_flush_icache (code, buf - code);
372 g_assert ((buf - code) <= 20);
374 ji = g_new0 (MonoJitInfo, 1);
375 ji->method = method;
376 ji->code_start = code;
377 ji->code_size = buf - code;
379 return ji;
383 MonoJitInfo*
384 mono_arch_create_jump_trampoline (MonoMethod *method)
386 guint8 *tramp;
387 MonoDomain* domain = mono_domain_get ();
389 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP);
390 return create_specific_tramp (method, tramp, domain);
394 * arch_create_jit_trampoline:
395 * @method: pointer to the method info
397 * Creates a trampoline function for virtual methods. If the created
398 * code is called it first starts JIT compilation of method,
399 * and then calls the newly created method. It also replaces the
400 * corresponding vtable entry (see mono_magic_trampoline).
402 * A trampoline consists of two parts: a main fragment, shared by all method
403 * trampolines, and some code specific to each method, which hard-codes a
404 * reference to that method and then calls the main fragment.
406 * The main fragment contains a call to 'arm_magic_trampoline', which performs
407 * call to the JIT compiler and substitutes the method-specific fragment with
408 * some code that directly calls the JIT-compiled method.
410 * Returns: a pointer to the newly created code
412 gpointer
413 mono_arch_create_jit_trampoline (MonoMethod *method)
415 guint8 *tramp;
416 MonoJitInfo *ji;
417 MonoDomain* domain = mono_domain_get ();
418 gpointer code_start;
420 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JIT);
421 ji = create_specific_tramp (method, tramp, domain);
422 code_start = ji->code_start;
423 g_free (ji);
425 return code_start;
428 gpointer
429 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 encoded_offset)
431 /* FIXME: implement! */
432 g_assert_not_reached ();
433 return NULL;