* src/vm/jit/sparc64/md-abi.h: The JIT stackframes now also includes the 6 parameter...
[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         /* calculate the patch position */
65
66         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
67
68         /* get the instruction before the exception point */
69
70         mcode = mcodeptr[-1];
71         
72         /* Calculate the branch displacement.  SPARC displacements regard current
73            PC as base => (branchmpc - 4 */
74         
75         disp = (targetmpc - (branchmpc - 4)) >> 2;
76         
77
78         /* check for BPcc or FBPfcc instruction */
79         if (((mcode >> 16) & 0xc1c0) == 0x0040) {
80         
81                 /* check branch displacement (19-bit)*/
82         
83                 if ((disp < (s4) 0xfffc0000) || (disp > (s4) 0x003ffff))
84                         vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x003ffff);
85         
86                 /* patch the branch instruction before the mcodeptr */
87         
88                 mcodeptr[-1] |= (disp & 0x007ffff);
89         }
90         /* check for BPr instruction */
91         else if (((mcode >> 16) & 0xd1c0) == 0x00c0) {
92
93                 /* check branch displacement (16-bit)*/
94         
95                 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x0007fff))
96                         vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x0007fff);
97                         
98                 /* patch the upper 2-bit of the branch displacement */
99                 mcodeptr[-1] |= ((disp & 0xc000) << 6);
100                         
101                 /* patch the lower 14-bit of the branch displacement */
102                 mcodeptr[-1] |= (disp & 0x003fff);
103                 
104         }
105         else
106                 assert(0);
107 }
108
109
110 /* md_stacktrace_get_returnaddress *********************************************
111
112    Returns the return address of the current stackframe, specified by
113    the passed stack pointer and the stack frame size.
114
115 *******************************************************************************/
116
117 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
118 {
119         u1 *ra;
120         /* flush register windows to the stack */
121         __asm__ ("flushw");
122
123         /* the return address resides in register i7, the last register in the
124          * 16-extended-word save area
125          */
126         ra = *((u1 **) (sp + 120 + BIAS));
127         
128         /* NOTE: on SPARC ra is the address of the call instruction */
129
130         return ra;
131 }
132
133 u1 *md_get_framepointer(u1 *sp)
134 {
135         u1 *ra;
136         /* flush register windows to the stack */
137         __asm__ ("flushw");
138
139         ra = *((u1 **) (sp + 112 + BIAS));
140
141         return ra;
142 }
143
144 /* md_codegen_get_pv_from_pc ***************************************************
145
146    This reconstructs and returns the PV of a method given a return address
147    pointer. (basically, same was as the generated code following the jump does)
148    
149    Machine code:
150
151    6b5b4000    jmpl    (pv)
152    10000000    nop
153    277afffe    ldah    pv,-2(ra)
154    237ba61c    lda     pv,-23012(pv)
155
156 *******************************************************************************/
157
158 u1 *md_codegen_get_pv_from_pc(u1 *ra)
159 {
160         u1 *pv;
161         u8  mcode;
162         u4  mcode_masked;
163         s2  offset;
164
165         pv = ra;
166
167         /* get the instruction word after jump and nop */
168         mcode = *((u4 *) (ra+8) );
169
170         /* check if we have 2 instructions (ldah, lda) */
171
172         mcode_masked = SHIFT_AND_MASK(mcode);
173
174         if (mcode_masked == 0x40001) {
175 #if 0
176                 /* get displacement of first instruction (ldah) */
177
178                 offset = (s4) (mcode << 16);
179                 pv += offset;
180
181                 /* get displacement of second instruction (lda) */
182
183                 mcode = *((u4 *) (ra + 1 * 4));
184
185                 assert((mcode >> 16) == 0x237b);
186
187                 offset = (s2) (mcode & 0x0000ffff);
188                 pv += offset;
189
190         } else {
191                 /* get displacement of first instruction (lda) */
192
193                 assert((mcode >> 16) == 0x237a);
194 #endif
195                 /* mask and extend the negative sign for the 13 bit immediate */
196                 offset = decode_13bit_imm(mcode);
197
198                 pv += offset;
199         }
200         else
201         {
202                 assert(0);
203         }
204
205         return pv;
206 }
207
208 /* md_get_method_patch_address *************************************************
209
210    Gets the patch address of the currently compiled method. The offset
211    is extracted from the load instruction(s) before the jump and added
212    to the right base address (PV or REG_METHODPTR).
213
214    INVOKESTATIC/SPECIAL:
215
216    dfdeffb8    ldx      [i5 - 72],o5
217    03c0f809    jmp      o5
218    00000000    nop
219
220    INVOKEVIRTUAL:
221
222    dc990000    ld       t9,0(a0)
223    df3e0000    ld       [g2 + 0],o5
224    03c0f809    jmp      o5
225    00000000    nop
226
227    INVOKEINTERFACE:
228
229    dc990000    ld       t9,0(a0)
230    df39ff90    ld       [g2 - 112],g2
231    df3e0018    ld       [g2 + 24],o5
232    03c0f809    jmp      o5
233    00000000    nop
234
235 *******************************************************************************/
236
237 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
238 {
239         u4  mcode, mcode_masked;
240         s4  offset;
241         u1 *pa;
242
243         /* go back to the actual load instruction (1 instruction before jump) */
244         /* ra is the address of the jump instruction on SPARC                 */
245         ra -= 1 * 4;
246
247         /* get first instruction word on current PC */
248
249         mcode = *((u4 *) ra);
250
251
252         /* check if we have 2 instructions (lui) */
253
254         if (IS_SETHI(mcode)) {
255                 /* XXX write a regression for this */
256                 assert(0);
257
258                 /* get displacement of first instruction (lui) */
259
260                 offset = (s4) (mcode << 16);
261
262                 /* get displacement of second instruction (daddiu) */
263
264                 mcode = *((u4 *) (ra + 1 * 4));
265
266                 assert((mcode >> 16) != 0x6739);
267
268                 offset += (s2) (mcode & 0x0000ffff);
269
270         } else {
271
272                 /* shift and maks rd */
273
274                 mcode_masked = (mcode >> 13) & 0x060fff;
275                 
276                 /* get the offset from the instruction */
277
278                 offset = decode_13bit_imm(mcode);
279
280                 /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
281
282                 if (mcode_masked == 0x0602c5) {
283                         /* in this case we use the passed method pointer */
284
285                         /* return NULL if no mptr was specified (used for replacement) */
286
287                         if (mptr == NULL)
288                                 return NULL;
289
290                         pa = mptr + offset;
291
292                 } else {
293                         /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
294
295                         assert(mcode_masked  == 0x0602fb);
296
297                         printf("data segment: pv=0x%08x, offset=%d\n", sfi->pv, offset);
298
299                         /* and get the final data segment address */
300
301                         pa = sfi->pv + offset;
302                 }
303         }
304
305         return pa;
306 }
307
308
309 /* md_cacheflush ***************************************************************
310
311    Calls the system's function to flush the instruction and data
312    cache.
313
314 *******************************************************************************/
315
316 void md_cacheflush(u1 *addr, s4 nbytes)
317 {
318         /* don't know yet */    
319 }
320
321
322 /* md_dcacheflush **************************************************************
323
324    Calls the system's function to flush the data cache.
325
326 *******************************************************************************/
327
328 void md_dcacheflush(u1 *addr, s4 nbytes)
329 {
330         /* XXX don't know yet */        
331 }
332
333
334 /* md_patch_replacement_point **************************************************
335
336    Patch the given replacement point.
337
338 *******************************************************************************/
339
340 #if defined(ENABLE_REPLACEMENT)
341 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
342 {
343         s4 disp;
344         u4 mcode;
345         
346         assert(0);
347
348         if (index < 0) {
349                 /* restore the patched-over instruction */
350                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
351         }
352         else {
353                 /* save the current machine code */
354                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
355
356                 /* build the machine code for the patch */
357                 disp = ((u4*)code->replacementstubs - (u4*)rp->pc)
358                            + index * REPLACEMENT_STUB_SIZE
359                            - 1;
360
361                 mcode = (((s4)(0x00))<<30) | ((0)<<29) | ((0x8)<<25) | (0x1<<22) | (0<<20)
362                           | (1 << 19 ) | ((disp) & 0x007ffff);
363
364                 /* write the new machine code */
365                 *(u4*)(rp->pc) = (u4) mcode;
366         }
367         
368 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
369         {
370                 u1* u1ptr = rp->pc;
371                 DISASSINSTR(u1ptr);
372                 fflush(stdout);
373         }
374 #endif
375                         
376         /* flush instruction cache */
377     /* md_icacheflush(rp->pc,4); */
378 }
379 #endif /* defined(ENABLE_REPLACEMENT) */
380
381 /*
382  * These are local overrides for various environment variables in Emacs.
383  * Please do not remove this and leave it at the end of the file, where
384  * Emacs will automagically detect them.
385  * ---------------------------------------------------------------------
386  * Local variables:
387  * mode: c
388  * indent-tabs-mode: t
389  * c-basic-offset: 4
390  * tab-width: 4
391  * End:
392  * vim:noexpandtab:sw=4:ts=4:
393  */