91aaf41286916d5334208f1e1d68afba6151e475
[cacao.git] / src / vm / jit / i386 / md.c
1 /* src/vm/jit/i386/md.c - machine dependent i386 functions
2
3    Copyright (C) 1996-2005, 2006 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    Contact: cacao@cacaojvm.org
26
27    Authors: Christian Thalinger
28             Edwin Steiner
29
30    $Id: md.c 7255 2007-01-29 21:39:38Z twisti $
31
32 */
33
34
35 #include "config.h"
36
37 #include <assert.h>
38
39 #include "vm/types.h"
40
41 #include "vm/global.h"
42
43 #include "vm/jit/asmpart.h"
44 #include "vm/jit/codegen-common.h"
45 #include "vm/jit/md.h"
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         (void) asm_md_init();
62 }
63
64
65 /* md_codegen_patch_branch *****************************************************
66
67    Back-patches a branch instruction.
68
69 *******************************************************************************/
70
71 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
72 {
73         s4 *mcodeptr;
74         s4  disp;                           /* branch displacement                */
75
76         /* calculate the patch position */
77
78         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
79
80         /* Calculate the branch displacement. */
81
82         disp = targetmpc - branchmpc;
83
84         /* I don't think we have to check for branch-displacement
85            overflow, +/-2GB should be enough. */
86
87         /* patch the branch instruction before the mcodeptr */
88
89         mcodeptr[-1] = disp;
90 }
91
92
93 /* md_stacktrace_get_returnaddress *********************************************
94
95    Returns the return address of the current stackframe, specified by
96    the passed stack pointer and the stack frame size.
97
98 *******************************************************************************/
99
100 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
101 {
102         u1 *ra;
103
104         /* on i386 the return address is above the current stack frame */
105
106         ra = *((u1 **) (sp + framesize));
107
108         return ra;
109 }
110
111
112 /* md_get_method_patch_address *************************************************
113
114    Gets the patch address of the currently compiled method. The offset
115    is extracted from the load instruction(s) before the jump and added
116    to the right base address (PV or REG_METHODPTR).
117
118    INVOKESTATIC/SPECIAL:
119
120    b9 30 00 49 b7             mov    $0xb7490030,%ecx
121    ff d1                      call   *%ecx
122
123    INVOKEVIRTUAL:
124
125    8b 08                      mov    (%eax),%ecx
126    8b 91 00 00 00 00          mov    0x0(%ecx),%edx
127    ff d2                      call   *%edx
128
129    INVOKEINTERFACE:
130
131    8b 08                      mov    (%eax),%ecx
132    8b 89 00 00 00 00          mov    0x0(%ecx),%ecx
133    8b 91 00 00 00 00          mov    0x0(%ecx),%edx
134    ff d2                      call   *%edx
135
136 *******************************************************************************/
137
138 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
139 {
140         u1  mcode;
141         s4  offset;
142         u1 *pa;                             /* patch address                      */
143
144         /* go back to the actual call instruction (2-bytes) */
145
146         ra = ra - 2;
147
148         /* get the last byte of the call */
149
150         mcode = ra[1];
151
152         /* check for the different calls */
153
154         if (mcode == 0xd1) {
155                 /* INVOKESTATIC/SPECIAL */
156
157                 /* patch address is 4-bytes before the call instruction */
158
159                 pa = ra - 4;
160         }
161         else if (mcode == 0xd2) {
162                 /* INVOKEVIRTUAL/INTERFACE */
163
164                 /* return NULL if no mptr was specified (used for replacement) */
165
166                 if (mptr == NULL)
167                         return NULL;
168
169                 /* Get the offset from the instruction (the offset address is
170                    4-bytes before the call instruction). */
171
172                 offset = *((s4 *) (ra - 4));
173
174                 /* add the offset to the method pointer */
175
176                 pa = mptr + offset;
177         }
178         else {
179                 /* catch any problems */
180
181                 pa = NULL; /* avoid warnings */
182
183                 vm_abort("couldn't find a proper call instruction sequence");
184         }
185
186         return pa;
187 }
188
189
190 /* md_codegen_get_pv_from_pc ***************************************************
191
192    On this architecture just a wrapper function to
193    codegen_get_pv_from_pc.
194
195 *******************************************************************************/
196
197 u1 *md_codegen_get_pv_from_pc(u1 *ra)
198 {
199         u1 *pv;
200
201         /* Get the start address of the function which contains this
202        address from the method table. */
203
204         pv = codegen_get_pv_from_pc(ra);
205
206         return pv;
207 }
208
209
210 /* md_cacheflush ***************************************************************
211
212    Calls the system's function to flush the instruction and data
213    cache.
214
215 *******************************************************************************/
216
217 void md_cacheflush(u1 *addr, s4 nbytes)
218 {
219         /* do nothing */
220 }
221
222
223 /* md_icacheflush **************************************************************
224
225    Calls the system's function to flush the instruction cache.
226
227 *******************************************************************************/
228
229 void md_icacheflush(u1 *addr, s4 nbytes)
230 {
231         /* do nothing */
232 }
233
234
235 /* md_dcacheflush **************************************************************
236
237    Calls the system's function to flush the data cache.
238
239 *******************************************************************************/
240
241 void md_dcacheflush(u1 *addr, s4 nbytes)
242 {
243         /* do nothing */
244 }
245
246
247 /* md_patch_replacement_point **************************************************
248
249    Patch the given replacement point.
250
251 *******************************************************************************/
252
253 #if defined(ENABLE_REPLACEMENT)
254 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
255 {
256         s4 disp;
257         u8 mcode;
258
259         /* XXX this is probably unsafe! */
260
261         if (index < 0) {
262                 /* write spinning instruction */
263                 *(u2*)(rp->pc) = 0xebfe;
264
265                 /* write 5th byte */
266                 rp->pc[4] = savedmcode[4];
267
268                 /* write first word */
269                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
270         }
271         else {
272                 /* save the current machine code */
273                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
274                 savedmcode[4] = rp->pc[4];
275
276                 /* build the machine code for the patch */
277                 disp = (code->replacementstubs - rp->pc)
278                            + index * REPLACEMENT_STUB_SIZE
279                            - 5;
280
281                 mcode = 0xe9 | ((u8) disp << 8);
282
283                 /* write spinning instruction */
284                 *(u2*)(rp->pc) = 0xebfe;
285
286                 /* write 5th byte */
287                 rp->pc[4] = (mcode >> 32);
288
289                 /* write first word */
290                 *(u4*)(rp->pc) = (u4) mcode;
291         }
292
293 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) && 0
294         {
295                 u1* u1ptr = rp->pc;
296                 DISASSINSTR(u1ptr);
297                 fflush(stdout);
298         }
299 #endif
300                         
301     /* XXX if required asm_cacheflush(rp->pc,8); */
302 }
303 #endif /* defined(ENABLE_REPLACEMENT) */
304
305 /*
306  * These are local overrides for various environment variables in Emacs.
307  * Please do not remove this and leave it at the end of the file, where
308  * Emacs will automagically detect them.
309  * ---------------------------------------------------------------------
310  * Local variables:
311  * mode: c
312  * indent-tabs-mode: t
313  * c-basic-offset: 4
314  * tab-width: 4
315  * End:
316  * vim:noexpandtab:sw=4:ts=4:
317  */