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