36ca91a5d32e620d3a074fa7987ebe8e48a58df8
[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 7935 2007-05-22 11:18:15Z 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_stacktrace_get_returnaddress *********************************************
64
65    Returns the return address of the current stackframe, specified by
66    the passed stack pointer and the stack frame size.
67
68 *******************************************************************************/
69
70 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
71 {
72         u1 *ra;
73
74         /* on x86_64 the return address is above the current stack frame */
75
76         ra = *((u1 **) (sp + framesize));
77
78         return ra;
79 }
80
81
82 /* md_get_method_patch_address *************************************************
83
84    Gets the patch address of the currently compiled method. The offset
85    is extracted from the load instruction(s) before the jump and added
86    to the right base address (PV or REG_METHODPTR).
87
88    INVOKESTATIC/SPECIAL:
89
90    4d 8b 15 e2 fe ff ff             mov    -286(%rip),%r10
91    49 ff d2                         rex64Z callq  *%r10
92
93    INVOKEVIRTUAL:
94
95    4c 8b 17                         mov    (%rdi),%r10
96    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
97    48 ff d3                         rex64 callq  *%rax
98
99    INVOKEINTERFACE:
100
101    4c 8b 17                         mov    (%rdi),%r10
102    4d 8b 92 00 00 00 00             mov    0x0(%r10),%r10
103    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
104    48 ff d3                         rex64 callq  *%r11
105
106 *******************************************************************************/
107
108 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
109 {
110         u1  mcode;
111         s4  offset;
112         u1 *pa;                             /* patch address                      */
113
114         /* go back to the actual call instruction (3-bytes) */
115
116         ra = ra - 3;
117
118         /* get the last byte of the call */
119
120         mcode = ra[2];
121
122         /* check for the different calls */
123
124         if (mcode == 0xd2) {
125                 /* INVOKESTATIC/SPECIAL */
126
127                 /* Get the offset from the instruction (the offset address is
128                    4-bytes before the call instruction). */
129
130                 offset = *((s4 *) (ra - 4));
131
132                 /* add the offset to the return address (IP-relative addressing) */
133
134                 pa = ra + offset;
135         }
136         else if (mcode == 0xd3) {
137                 /* INVOKEVIRTUAL/INTERFACE */
138
139                 /* return NULL if no mptr was specified (used for replacement) */
140
141                 if (mptr == NULL)
142                         return NULL;
143
144                 /* Get the offset from the instruction (the offset address is
145                    4-bytes before the call instruction). */
146
147                 offset = *((s4 *) (ra - 4));
148
149                 /* add the offset to the method pointer */
150
151                 pa = mptr + offset;
152         }
153         else {
154                 /* catch any problems */
155
156                 vm_abort("md_get_method_patch_address: unknown instruction %x", mcode);
157         }
158
159         return pa;
160 }
161
162
163 /* md_codegen_get_pv_from_pc ***************************************************
164
165    On this architecture just a wrapper function to
166    codegen_get_pv_from_pc.
167
168 *******************************************************************************/
169
170 u1 *md_codegen_get_pv_from_pc(u1 *ra)
171 {
172         u1 *pv;
173
174         /* Get the start address of the function which contains this
175        address from the method table. */
176
177         pv = codegen_get_pv_from_pc(ra);
178
179         return pv;
180 }
181
182
183 /* md_cacheflush ***************************************************************
184
185    Calls the system's function to flush the instruction and data
186    cache.
187
188 *******************************************************************************/
189
190 void md_cacheflush(u1 *addr, s4 nbytes)
191 {
192         /* do nothing */
193 }
194
195
196 /* md_icacheflush **************************************************************
197
198    Calls the system's function to flush the instruction cache.
199
200 *******************************************************************************/
201
202 void md_icacheflush(u1 *addr, s4 nbytes)
203 {
204         /* do nothing */
205 }
206
207
208 /* md_dcacheflush **************************************************************
209
210    Calls the system's function to flush the data cache.
211
212 *******************************************************************************/
213
214 void md_dcacheflush(u1 *addr, s4 nbytes)
215 {
216         /* do nothing */
217 }
218
219
220 /* md_patch_replacement_point **************************************************
221
222    Patch the given replacement point.
223
224 *******************************************************************************/
225
226 #if defined(ENABLE_REPLACEMENT)
227 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
228 {
229         s4 disp;
230         u8 mcode;
231
232         /* XXX this is probably unsafe! */
233
234         if (index < 0) {
235                 /* write spinning instruction */
236                 *(u2*)(rp->pc) = 0xebfe;
237
238                 /* write 5th byte */
239                 rp->pc[4] = savedmcode[4];
240
241                 /* write first word */
242                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
243         }
244         else {
245                 /* save the current machine code */
246                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
247                 savedmcode[4] = rp->pc[4];
248
249                 /* build the machine code for the patch */
250                 disp = (code->replacementstubs - rp->pc)
251                            + index * REPLACEMENT_STUB_SIZE
252                            - 5;
253
254                 mcode = 0xe9 | ((u8) disp << 8);
255
256                 /* write spinning instruction */
257                 *(u2*)(rp->pc) = 0xebfe;
258
259                 /* write 5th byte */
260                 rp->pc[4] = (mcode >> 32);
261
262                 /* write first word */
263                 *(u4*)(rp->pc) = (u4) mcode;
264         }
265
266 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) && 0
267         {
268                 u1* u1ptr = rp->pc;
269                 DISASSINSTR(u1ptr);
270                 fflush(stdout);
271         }
272 #endif
273                         
274     /* XXX if required asm_cacheflush(rp->pc,8); */
275 }
276 #endif /* defined(ENABLE_REPLACEMENT) */
277
278 /*
279  * These are local overrides for various environment variables in Emacs.
280  * Please do not remove this and leave it at the end of the file, where
281  * Emacs will automagically detect them.
282  * ---------------------------------------------------------------------
283  * Local variables:
284  * mode: c
285  * indent-tabs-mode: t
286  * c-basic-offset: 4
287  * tab-width: 4
288  * End:
289  * vim:noexpandtab:sw=4:ts=4:
290  */