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