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