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