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