* src/vm/jit/sparc64/emit.c: Implemented trace enter/exit 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_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
134         return pv;
135 }
136
137 /* md_get_method_patch_address *************************************************
138
139    Gets the patch address of the currently compiled method. The offset
140    is extracted from the load instruction(s) before the jump and added
141    to the right base address (PV or REG_METHODPTR).
142
143    INVOKESTATIC/SPECIAL:
144
145    dfdeffb8    ldx      [i5 - 72],o5
146    03c0f809    jmp      o5
147    00000000    nop
148
149    INVOKEVIRTUAL:
150
151    dc990000    ld       t9,0(a0)
152    df3e0000    ld       [g2 + 0],o5
153    03c0f809    jmp      o5
154    00000000    nop
155
156    INVOKEINTERFACE:
157
158    dc990000    ld       t9,0(a0)
159    df39ff90    ld       [g2 - 112],g2
160    df3e0018    ld       [g2 + 24],o5
161    03c0f809    jmp      o5
162    00000000    nop
163
164 *******************************************************************************/
165
166 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
167 {
168         u4  mcode, mcode_masked;
169         s4  offset;
170         u1 *pa;
171
172         /* go back to the actual load instruction (1 instruction before jump) */
173         /* ra is the address of the jump instruction on SPARC                 */
174         ra -= 1 * 4;
175
176         /* get first instruction word on current PC */
177
178         mcode = *((u4 *) ra);
179
180
181         /* check if we have 2 instructions (lui) */
182
183         if (IS_SETHI(mcode)) {
184                 /* XXX write a regression for this */
185                 assert(0);
186
187                 /* get displacement of first instruction (lui) */
188
189                 offset = (s4) (mcode << 16);
190
191                 /* get displacement of second instruction (daddiu) */
192
193                 mcode = *((u4 *) (ra + 1 * 4));
194
195                 assert((mcode >> 16) != 0x6739);
196
197                 offset += (s2) (mcode & 0x0000ffff);
198
199         } else {
200
201                 /* shift and maks rd */
202
203                 mcode_masked = (mcode >> 13) & 0x060fff;
204                 
205                 /* get the offset from the instruction */
206
207                 offset = decode_13bit_imm(mcode);
208
209                 /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
210
211                 if (mcode_masked == 0x0602c5) {
212                         /* in this case we use the passed method pointer */
213
214                         pa = mptr + offset;
215
216                 } else {
217                         /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
218
219                         assert(mcode_masked  == 0x0602fb);
220
221                         /* and get the final data segment address */
222
223                         pa = sfi->pv + offset;
224                 }
225         }
226
227         return pa;
228 }
229
230
231 /* md_cacheflush ***************************************************************
232
233    Calls the system's function to flush the instruction and data
234    cache.
235
236 *******************************************************************************/
237
238 void md_cacheflush(u1 *addr, s4 nbytes)
239 {
240         /* don't know yet */    
241 }
242
243
244 /* md_icacheflush **************************************************************
245
246    Calls the system's function to flush the instruction cache.
247
248 *******************************************************************************/
249
250 void md_icacheflush(u1 *addr, s4 nbytes)
251 {
252         /* don't know yet */    
253 }
254
255
256 /* md_patch_replacement_point **************************************************
257
258    Patch the given replacement point.
259
260 *******************************************************************************/
261
262 void md_patch_replacement_point(rplpoint *rp)
263 {
264     u8 mcode;
265
266         /* save the current machine code */
267         mcode = *(u4*)rp->pc;
268
269         /* write the new machine code */
270     *(u4*)(rp->pc) = (u4) rp->mcode;
271
272         /* store saved mcode */
273         rp->mcode = mcode;
274         
275 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
276         {
277                 u1* u1ptr = rp->pc;
278                 DISASSINSTR(u1ptr);
279                 fflush(stdout);
280         }
281 #endif
282                         
283         /* flush instruction cache */
284     /* md_icacheflush(rp->pc,4); */
285 }
286
287 /*
288  * These are local overrides for various environment variables in Emacs.
289  * Please do not remove this and leave it at the end of the file, where
290  * Emacs will automagically detect them.
291  * ---------------------------------------------------------------------
292  * Local variables:
293  * mode: c
294  * indent-tabs-mode: t
295  * c-basic-offset: 4
296  * tab-width: 4
297  * End:
298  * vim:noexpandtab:sw=4:ts=4:
299  */