Merged r5476 from trunk:
[cacao.git] / src / vm / jit / sparc64 / md.c
1
2 #include <assert.h>
3
4 #include "config.h"
5
6 #include "vm/types.h"
7
8 #include "vm/jit/sparc64/md-abi.h"
9
10 #include "vm/exceptions.h"
11 #include "vm/stringlocal.h"
12 #include "vm/jit/asmpart.h"
13 #include "vm/jit/stacktrace.h"
14
15 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
16 #include "vm/options.h" /* XXX debug */
17 #include "vm/jit/disass.h" /* XXX debug */
18 #endif
19
20
21 /* md_init *********************************************************************
22
23    Do some machine dependent initialization.
24
25 *******************************************************************************/
26
27 void md_init(void)
28 {
29         /* do nothing */
30 }
31
32
33 /* md_stacktrace_get_returnaddress *********************************************
34
35    Returns the return address of the current stackframe, specified by
36    the passed stack pointer and the stack frame size.
37
38 *******************************************************************************/
39
40 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
41 {
42         u1 *ra;
43         /* flush register windows to the stack */
44         __asm__ ("flushw");
45
46         /* the return address resides in register i7, the last register in the
47          * 16-extended-word save area
48          */
49         ra = *((u1 **) (sp + 120));
50         
51         /* ra is the address of the call instr, advance to the real return address  */
52         ra += 8;
53
54         return ra;
55 }
56
57
58 /* md_codegen_get_pv_from_pc ***************************************************
59
60    This reconstructs and returns the PV of a method given a return address
61    pointer. (basically, same was as the generated code following the jump does)
62    
63    Machine code:
64
65    6b5b4000    jsr     (pv)
66    277afffe    ldah    pv,-2(ra)
67    237ba61c    lda     pv,-23012(pv)
68
69 *******************************************************************************/
70
71 u1 *md_codegen_get_pv_from_pc(u1 *ra)
72 {
73         u1 *pv;
74         u4  mcode;
75         s4  offset;
76
77         pv = ra;
78
79         /* get first instruction word after jump */
80
81         mcode = *((u4 *) ra);
82
83         /* check if we have 2 instructions (ldah, lda) */
84
85         if ((mcode >> 16) == 0x277a) {
86                 /* get displacement of first instruction (ldah) */
87
88                 offset = (s4) (mcode << 16);
89                 pv += offset;
90
91                 /* get displacement of second instruction (lda) */
92
93                 mcode = *((u4 *) (ra + 1 * 4));
94
95                 assert((mcode >> 16) == 0x237b);
96
97                 offset = (s2) (mcode & 0x0000ffff);
98                 pv += offset;
99
100         } else {
101                 /* get displacement of first instruction (lda) */
102
103                 assert((mcode >> 16) == 0x237a);
104
105                 offset = (s2) (mcode & 0x0000ffff);
106                 pv += offset;
107         }
108
109         return pv;
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    dfdeffb8    ld       s8,-72(s8)
121    03c0f809    jalr     s8
122    00000000    nop
123
124    INVOKEVIRTUAL:
125
126    dc990000    ld       t9,0(a0)
127    df3e0000    ld       s8,0(t9)
128    03c0f809    jalr     s8
129    00000000    nop
130
131    INVOKEINTERFACE:
132
133    dc990000    ld       t9,0(a0)
134    df39ff90    ld       t9,-112(t9)
135    df3e0018    ld       s8,24(t9)
136    03c0f809    jalr     s8
137    00000000    nop
138
139 *******************************************************************************/
140
141 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
142 {
143         u4  mcode;
144         s4  offset;
145         u1 *pa;
146
147         /* go back to the actual load instruction (3 instructions on MIPS) */
148
149         ra -= 3 * 4;
150
151         /* get first instruction word on current PC */
152
153         mcode = *((u4 *) ra);
154
155         /* check if we have 2 instructions (lui) */
156
157         if ((mcode >> 16) == 0x3c19) {
158                 /* XXX write a regression for this */
159                 assert(0);
160
161                 /* get displacement of first instruction (lui) */
162
163                 offset = (s4) (mcode << 16);
164
165                 /* get displacement of second instruction (daddiu) */
166
167                 mcode = *((u4 *) (ra + 1 * 4));
168
169                 assert((mcode >> 16) != 0x6739);
170
171                 offset += (s2) (mcode & 0x0000ffff);
172
173         } else {
174                 /* get first instruction (ld) */
175
176                 mcode = *((u4 *) ra);
177
178                 /* get the offset from the instruction */
179
180                 offset = (s2) (mcode & 0x0000ffff);
181
182                 /* check for call with REG_METHODPTR: ld s8,x(t9) */
183
184 #if SIZEOF_VOID_P == 8
185                 if ((mcode >> 16) == 0xdf3e) {
186 #else
187                 if ((mcode >> 16) == 0x8f3e) {
188 #endif
189                         /* in this case we use the passed method pointer */
190
191                         pa = mptr + offset;
192
193                 } else {
194                         /* in the normal case we check for a `ld s8,x(s8)' instruction */
195
196 #if SIZEOF_VOID_P == 8
197                         assert((mcode >> 16) == 0xdfde);
198 #else
199                         assert((mcode >> 16) == 0x8fde);
200 #endif
201
202                         /* and get the final data segment address */
203
204                         pa = sfi->pv + offset;
205                 }
206         }
207
208         return pa;
209 }
210
211
212 /* md_cacheflush ***************************************************************
213
214    Calls the system's function to flush the instruction and data
215    cache.
216
217 *******************************************************************************/
218
219 void md_cacheflush(u1 *addr, s4 nbytes)
220 {
221         /* don't know yet */    
222 }
223
224
225 /* md_icacheflush **************************************************************
226
227    Calls the system's function to flush the instruction cache.
228
229 *******************************************************************************/
230
231 void md_icacheflush(u1 *addr, s4 nbytes)
232 {
233         /* don't know yet */    
234 }
235
236
237 /* md_patch_replacement_point **************************************************
238
239    Patch the given replacement point.
240
241 *******************************************************************************/
242
243 void md_patch_replacement_point(rplpoint *rp)
244 {
245     u8 mcode;
246
247         /* save the current machine code */
248         mcode = *(u4*)rp->pc;
249
250         /* write the new machine code */
251     *(u4*)(rp->pc) = (u4) rp->mcode;
252
253         /* store saved mcode */
254         rp->mcode = mcode;
255         
256 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
257         {
258                 u1* u1ptr = rp->pc;
259                 DISASSINSTR(u1ptr);
260                 fflush(stdout);
261         }
262 #endif
263                         
264         /* flush instruction cache */
265     /* md_icacheflush(rp->pc,4); */
266 }
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  */