* src/vm/jit/sparc64/*: implemented patching (partly), adherent fixes.
[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 /* shift away 13-bit immediate,  mask rd and rs1    */
21 #define SHIFT_AND_MASK(instr) \
22         ((instr >> 13) & 0x60fc1)
23
24 #define IS_SETHI(instr) \
25         ((instr & 0xc1c00000)  == 0x00800000)
26
27 inline s2 decode_13bit_imm(u4 instr) {
28         s2 imm;
29
30         /* mask everything else in the instruction */
31         imm = instr & 0x00001fff;
32
33         /* sign extend 13-bit to 16-bit */
34         imm <<= 3;
35         imm >>= 3;
36
37         return imm;
38 }
39
40 /* md_init *********************************************************************
41
42    Do some machine dependent initialization.
43
44 *******************************************************************************/
45
46 void md_init(void)
47 {
48         /* do nothing */
49 }
50
51
52 /* md_codegen_patch_branch *****************************************************
53
54    Back-patches a branch instruction.
55
56 *******************************************************************************/
57
58 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
59 {
60         s4 *mcodeptr;
61         s4  mcode;
62         s4  disp;                           /* branch displacement                */
63
64         assert(0);
65
66         /* calculate the patch position */
67
68         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
69
70         /* get the instruction before the exception point */
71
72         mcode = mcodeptr[-1];
73
74         /* check for BPcc instruction */
75         if (((mcode >> 16) & 0xc1c0) != 0x0040)
76                 assert(0);
77
78         /* Calculate the branch displacement.  For branches we need a
79            displacement relative and shifted to the branch PC. */
80
81         disp = (targetmpc - branchmpc) >> 2;
82
83         /* check branch displacement */
84
85         if ((disp < (s4) 0xfffc0000) || (disp > (s4) 0x003ffff))
86                 vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x003ffff);
87
88         /* patch the branch instruction before the mcodeptr */
89
90         mcodeptr[-1] |= (disp & 0x003ffff);
91 }
92
93
94 /* md_stacktrace_get_returnaddress *********************************************
95
96    Returns the return address of the current stackframe, specified by
97    the passed stack pointer and the stack frame size.
98
99 *******************************************************************************/
100
101 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
102 {
103         u1 *ra;
104         /* flush register windows to the stack */
105         __asm__ ("flushw");
106
107         /* the return address resides in register i7, the last register in the
108          * 16-extended-word save area
109          */
110         ra = *((u1 **) (sp + 120 + BIAS));
111         
112         /* ra is the address of the call instr, advance to the real return address  */
113         ra += 8;
114
115         return ra;
116 }
117
118
119 /* md_codegen_get_pv_from_pc ***************************************************
120
121    This reconstructs and returns the PV of a method given a return address
122    pointer. (basically, same was as the generated code following the jump does)
123    
124    Machine code:
125
126    6b5b4000    jmpl    (pv)
127    10000000    nop
128    277afffe    ldah    pv,-2(ra)
129    237ba61c    lda     pv,-23012(pv)
130
131 *******************************************************************************/
132
133 u1 *md_codegen_get_pv_from_pc(u1 *ra)
134 {
135         u1 *pv;
136         u8  mcode;
137         u4  mcode_masked;
138         s2  offset;
139
140         pv = ra;
141
142         /* get the instruction word after jump and nop */
143         mcode = *((u4 *) (ra+8) );
144
145         /* check if we have 2 instructions (ldah, lda) */
146
147         mcode_masked = SHIFT_AND_MASK(mcode);
148
149         if (mcode_masked == 0x40001) {
150 #if 0
151                 /* get displacement of first instruction (ldah) */
152
153                 offset = (s4) (mcode << 16);
154                 pv += offset;
155
156                 /* get displacement of second instruction (lda) */
157
158                 mcode = *((u4 *) (ra + 1 * 4));
159
160                 assert((mcode >> 16) == 0x237b);
161
162                 offset = (s2) (mcode & 0x0000ffff);
163                 pv += offset;
164
165         } else {
166                 /* get displacement of first instruction (lda) */
167
168                 assert((mcode >> 16) == 0x237a);
169 #endif
170                 /* mask and extend the negative sign for the 13 bit immediate */
171                 offset = decode_13bit_imm(mcode);
172
173                 pv += offset;
174         }
175         else
176         {
177                 assert(0);
178         }
179
180         return pv;
181 }
182
183 /* md_get_method_patch_address *************************************************
184
185    Gets the patch address of the currently compiled method. The offset
186    is extracted from the load instruction(s) before the jump and added
187    to the right base address (PV or REG_METHODPTR).
188
189    INVOKESTATIC/SPECIAL:
190
191    dfdeffb8    ldx      [i5 - 72],o5
192    03c0f809    jmp      o5
193    00000000    nop
194
195    INVOKEVIRTUAL:
196
197    dc990000    ld       t9,0(a0)
198    df3e0000    ld       [g2 + 0],o5
199    03c0f809    jmp      o5
200    00000000    nop
201
202    INVOKEINTERFACE:
203
204    dc990000    ld       t9,0(a0)
205    df39ff90    ld       [g2 - 112],g2
206    df3e0018    ld       [g2 + 24],o5
207    03c0f809    jmp      o5
208    00000000    nop
209
210 *******************************************************************************/
211
212 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
213 {
214         u4  mcode, mcode_masked;
215         s4  offset;
216         u1 *pa;
217
218         /* go back to the actual load instruction (1 instruction before jump) */
219         /* ra is the address of the jump instruction on SPARC                 */
220         ra -= 1 * 4;
221
222         /* get first instruction word on current PC */
223
224         mcode = *((u4 *) ra);
225
226
227         /* check if we have 2 instructions (lui) */
228
229         if (IS_SETHI(mcode)) {
230                 /* XXX write a regression for this */
231                 assert(0);
232
233                 /* get displacement of first instruction (lui) */
234
235                 offset = (s4) (mcode << 16);
236
237                 /* get displacement of second instruction (daddiu) */
238
239                 mcode = *((u4 *) (ra + 1 * 4));
240
241                 assert((mcode >> 16) != 0x6739);
242
243                 offset += (s2) (mcode & 0x0000ffff);
244
245         } else {
246
247                 /* shift and maks rd */
248
249                 mcode_masked = (mcode >> 13) & 0x060fff;
250                 
251                 /* get the offset from the instruction */
252
253                 offset = decode_13bit_imm(mcode);
254
255                 /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
256
257                 if (mcode_masked == 0x0602c5) {
258                         /* in this case we use the passed method pointer */
259
260                         pa = mptr + offset;
261
262                 } else {
263                         /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
264
265                         assert(mcode_masked  == 0x0602fb);
266
267                         printf("data segment: pv=0x%08x, offset=%d\n", sfi->pv, offset);
268
269                         /* and get the final data segment address */
270
271                         pa = sfi->pv + offset;
272                 }
273         }
274
275         return pa;
276 }
277
278
279 /* md_cacheflush ***************************************************************
280
281    Calls the system's function to flush the instruction and data
282    cache.
283
284 *******************************************************************************/
285
286 void md_cacheflush(u1 *addr, s4 nbytes)
287 {
288         /* don't know yet */    
289 }
290
291
292 /* md_icacheflush **************************************************************
293
294    Calls the system's function to flush the instruction cache.
295
296 *******************************************************************************/
297
298 void md_icacheflush(u1 *addr, s4 nbytes)
299 {
300         /* don't know yet */    
301 }
302
303
304 /* md_patch_replacement_point **************************************************
305
306    Patch the given replacement point.
307
308 *******************************************************************************/
309
310 void md_patch_replacement_point(rplpoint *rp)
311 {
312     u8 mcode;
313
314         /* save the current machine code */
315         mcode = *(u4*)rp->pc;
316
317         /* write the new machine code */
318     *(u4*)(rp->pc) = (u4) rp->mcode;
319
320         /* store saved mcode */
321         rp->mcode = mcode;
322         
323 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
324         {
325                 u1* u1ptr = rp->pc;
326                 DISASSINSTR(u1ptr);
327                 fflush(stdout);
328         }
329 #endif
330                         
331         /* flush instruction cache */
332     /* md_icacheflush(rp->pc,4); */
333 }
334
335 /*
336  * These are local overrides for various environment variables in Emacs.
337  * Please do not remove this and leave it at the end of the file, where
338  * Emacs will automagically detect them.
339  * ---------------------------------------------------------------------
340  * Local variables:
341  * mode: c
342  * indent-tabs-mode: t
343  * c-basic-offset: 4
344  * tab-width: 4
345  * End:
346  * vim:noexpandtab:sw=4:ts=4:
347  */