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