816a5c8bc24e8469f3220ce858f2efb45b36ece1
[cacao.git] / src / vm / jit / x86_64 / md.c
1 /* src/vm/jit/x86_64/md.c - machine dependent x86_64 functions
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    $Id: md.c 7486 2007-03-08 13:50:07Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <stdlib.h>
34
35 #include "vm/jit/x86_64/md-abi.h"
36
37 #if defined(ENABLE_THREADS)
38 # include "threads/native/threads.h"
39 #endif
40
41 #include "vm/jit/asmpart.h"
42 #include "vm/jit/codegen-common.h"
43 #include "vm/jit/stacktrace.h"
44
45 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
46 #include "vmcore/options.h" /* XXX debug */
47 #include "vm/jit/disass.h" /* XXX debug */
48 #endif
49
50
51 /* md_init *********************************************************************
52
53    Do some machine dependent initialization.
54
55 *******************************************************************************/
56
57 void md_init(void)
58 {
59         /* nothing to do */
60 }
61
62
63 /* md_codegen_patch_branch *****************************************************
64
65    Back-patches a branch instruction.
66
67 *******************************************************************************/
68
69 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
70 {
71         s4 *mcodeptr;
72         s4  disp;                           /* branch displacement                */
73
74         /* calculate the patch position */
75
76         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
77
78         /* Calculate the branch displacement. */
79
80         disp = targetmpc - branchmpc;
81
82         /* I don't think we have to check for branch-displacement
83            overflow.  +/-2GB should be enough. */
84
85         /* patch the branch instruction before the mcodeptr */
86
87         mcodeptr[-1] = disp;
88 }
89
90
91 /* md_stacktrace_get_returnaddress *********************************************
92
93    Returns the return address of the current stackframe, specified by
94    the passed stack pointer and the stack frame size.
95
96 *******************************************************************************/
97
98 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
99 {
100         u1 *ra;
101
102         /* on x86_64 the return address is above the current stack frame */
103
104         ra = *((u1 **) (sp + framesize));
105
106         return ra;
107 }
108
109
110 /* md_get_method_patch_address *************************************************
111
112    Gets the patch address of the currently compiled method. The offset
113    is extracted from the load instruction(s) before the jump and added
114    to the right base address (PV or REG_METHODPTR).
115
116    INVOKESTATIC/SPECIAL:
117
118    4d 8b 15 e2 fe ff ff             mov    -286(%rip),%r10
119    49 ff d2                         rex64Z callq  *%r10
120
121    INVOKEVIRTUAL:
122
123    4c 8b 17                         mov    (%rdi),%r10
124    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
125    48 ff d3                         rex64 callq  *%rax
126
127    INVOKEINTERFACE:
128
129    4c 8b 17                         mov    (%rdi),%r10
130    4d 8b 92 00 00 00 00             mov    0x0(%r10),%r10
131    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
132    48 ff d3                         rex64 callq  *%r11
133
134 *******************************************************************************/
135
136 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
137 {
138         u1  mcode;
139         s4  offset;
140         u1 *pa;                             /* patch address                      */
141
142         /* go back to the actual call instruction (3-bytes) */
143
144         ra = ra - 3;
145
146         /* get the last byte of the call */
147
148         mcode = ra[2];
149
150         /* check for the different calls */
151
152         if (mcode == 0xd2) {
153                 /* INVOKESTATIC/SPECIAL */
154
155                 /* Get the offset from the instruction (the offset address is
156                    4-bytes before the call instruction). */
157
158                 offset = *((s4 *) (ra - 4));
159
160                 /* add the offset to the return address (IP-relative addressing) */
161
162                 pa = ra + offset;
163         }
164         else if (mcode == 0xd3) {
165                 /* INVOKEVIRTUAL/INTERFACE */
166
167                 /* return NULL if no mptr was specified (used for replacement) */
168
169                 if (mptr == NULL)
170                         return NULL;
171
172                 /* Get the offset from the instruction (the offset address is
173                    4-bytes before the call instruction). */
174
175                 offset = *((s4 *) (ra - 4));
176
177                 /* add the offset to the method pointer */
178
179                 pa = mptr + offset;
180         }
181         else {
182                 /* catch any problems */
183
184                 assert(0);
185         }
186
187         return pa;
188 }
189
190
191 /* md_codegen_get_pv_from_pc ***************************************************
192
193    On this architecture just a wrapper function to
194    codegen_get_pv_from_pc.
195
196 *******************************************************************************/
197
198 u1 *md_codegen_get_pv_from_pc(u1 *ra)
199 {
200         u1 *pv;
201
202         /* Get the start address of the function which contains this
203        address from the method table. */
204
205         pv = codegen_get_pv_from_pc(ra);
206
207         return pv;
208 }
209
210
211 /* md_cacheflush ***************************************************************
212
213    Calls the system's function to flush the instruction and data
214    cache.
215
216 *******************************************************************************/
217
218 void md_cacheflush(u1 *addr, s4 nbytes)
219 {
220         /* do nothing */
221 }
222
223
224 /* md_icacheflush **************************************************************
225
226    Calls the system's function to flush the instruction cache.
227
228 *******************************************************************************/
229
230 void md_icacheflush(u1 *addr, s4 nbytes)
231 {
232         /* do nothing */
233 }
234
235
236 /* md_dcacheflush **************************************************************
237
238    Calls the system's function to flush the data cache.
239
240 *******************************************************************************/
241
242 void md_dcacheflush(u1 *addr, s4 nbytes)
243 {
244         /* do nothing */
245 }
246
247
248 /* md_patch_replacement_point **************************************************
249
250    Patch the given replacement point.
251
252 *******************************************************************************/
253
254 #if defined(ENABLE_REPLACEMENT)
255 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
256 {
257         s4 disp;
258         u8 mcode;
259
260         /* XXX this is probably unsafe! */
261
262         if (index < 0) {
263                 /* write spinning instruction */
264                 *(u2*)(rp->pc) = 0xebfe;
265
266                 /* write 5th byte */
267                 rp->pc[4] = savedmcode[4];
268
269                 /* write first word */
270                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
271         }
272         else {
273                 /* save the current machine code */
274                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
275                 savedmcode[4] = rp->pc[4];
276
277                 /* build the machine code for the patch */
278                 disp = (code->replacementstubs - rp->pc)
279                            + index * REPLACEMENT_STUB_SIZE
280                            - 5;
281
282                 mcode = 0xe9 | ((u8) disp << 8);
283
284                 /* write spinning instruction */
285                 *(u2*)(rp->pc) = 0xebfe;
286
287                 /* write 5th byte */
288                 rp->pc[4] = (mcode >> 32);
289
290                 /* write first word */
291                 *(u4*)(rp->pc) = (u4) mcode;
292         }
293
294 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) && 0
295         {
296                 u1* u1ptr = rp->pc;
297                 DISASSINSTR(u1ptr);
298                 fflush(stdout);
299         }
300 #endif
301                         
302     /* XXX if required asm_cacheflush(rp->pc,8); */
303 }
304 #endif /* defined(ENABLE_REPLACEMENT) */
305
306 /*
307  * These are local overrides for various environment variables in Emacs.
308  * Please do not remove this and leave it at the end of the file, where
309  * Emacs will automagically detect them.
310  * ---------------------------------------------------------------------
311  * Local variables:
312  * mode: c
313  * indent-tabs-mode: t
314  * c-basic-offset: 4
315  * tab-width: 4
316  * End:
317  * vim:noexpandtab:sw=4:ts=4:
318  */