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