f7f6f2f1de7566e1a48b73fb7b8d660857507b58
[cacao.git] / src / vm / jit / sparc64 / md.c
1 /* src/vm/jit/sparc64/md.c - machine dependent SPARC functions
2
3    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    $Id: md.c 6265 2007-01-02 20:40:57Z edwin $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33
34
35 #include "vm/types.h"
36
37 #include "vm/jit/sparc64/md-abi.h"
38
39 #include "vm/exceptions.h"
40 #include "vm/stringlocal.h"
41 #include "vm/jit/asmpart.h"
42 #include "vm/jit/stacktrace.h"
43
44 /* assembler function prototypes **********************************************/
45 void asm_store_fp_state_reg(u8 *mem);
46 void asm_load_fp_state_reg(u8 *mem);
47
48
49
50 /* shift away 13-bit immediate,  mask rd and rs1    */
51 #define SHIFT_AND_MASK(instr) \
52         ((instr >> 13) & 0x60fc1)
53
54 /* NOP is defined as a SETHI instruction with rd and imm. set to zero */
55 /* therefore we check if the 22-bit immediate is zero */
56 #define IS_SETHI(instr) \
57         (((instr & 0xc1c00000)  == 0x01000000) \
58         && ((instr & 0x3fffff) != 0x0))
59         
60 #define IS_LDX_IMM(instr) \
61         (((instr >> 13) & 0x60fc1) == 0x602c1)
62         
63 #define IS_SUB(instr) \
64         (((instr >> 13) & 0x60fc0) == 0x40100)
65
66 inline s2 decode_13bit_imm(u4 instr) {
67         s2 imm;
68
69         /* mask everything else in the instruction */
70         imm = instr & 0x00001fff;
71
72         /* sign extend 13-bit to 16-bit */
73         imm <<= 3;
74         imm >>= 3;
75
76         return imm;
77 }
78
79 /* md_init *********************************************************************
80
81    Do some machine dependent initialization.
82
83 *******************************************************************************/
84
85 void md_init(void)
86 {
87         /* do nothing */
88 }
89
90
91 /* md_stacktrace_get_returnaddress *********************************************
92
93    Returns the return address of the current stackframe, specified by
94    the passed stack pointer and the stack frame size.
95
96 *******************************************************************************/
97
98 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
99 {
100         u1 *ra;
101         /* flush register windows to the stack */
102         __asm__ ("flushw");
103
104         /* the return address resides in register i7, the last register in the
105          * 16-extended-word save area
106          */
107         ra = *((u1 **) (sp + 120 + BIAS));
108         
109         /* NOTE: on SPARC ra is the address of the call instruction */
110
111         return ra;
112 }
113
114 u1 *md_get_framepointer(u1 *sp)
115 {
116         u1 *fp;
117         /* flush register windows to the stack */
118         __asm__ ("flushw");
119
120         fp = *((u1 **) (sp + 112 + BIAS));
121
122         return fp;
123 }
124
125 u1 *md_get_pv_from_stackframe(u1 *sp)
126 {
127         u1 *pv;
128         /* flush register windows to the stack */
129         __asm__ ("flushw");
130
131         pv = *((u1 **) (sp + 104 + BIAS));
132
133         return pv;
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         s4  offset;
155
156         pv = ra;
157
158         /* get the instruction word after jump and nop */
159         mcode = *((u4 *) (ra+8) );
160
161         /* check if we have a sethi insruction */
162         if (IS_SETHI(mcode)) {
163                 s4 xor_imm;
164                                 
165                 /* get 22-bit immediate of sethi instruction */
166                 offset = (s4) (mcode & 0x3fffff);
167                 offset = offset << 10;
168                 
169                 /* now the xor */
170                 mcode = *((u4 *) (ra+12) );
171                 xor_imm = decode_13bit_imm(mcode);
172                 
173                 offset ^= xor_imm;       
174         }
175         else {
176                 u4 mcode_masked;
177                 
178                 mcode_masked = SHIFT_AND_MASK(mcode);
179
180                 assert(mcode_masked == 0x40001);
181
182                 /* mask and extend the negative sign for the 13 bit immediate */
183                 offset = decode_13bit_imm(mcode);
184         }
185         
186         pv += offset;
187
188         return pv;
189 }
190
191 /* md_get_method_patch_address *************************************************
192
193    Gets the patch address of the currently compiled method. The offset
194    is extracted from the load instruction(s) before the jump and added
195    to the right base address (PV or REG_METHODPTR).
196
197    INVOKESTATIC/SPECIAL:
198
199    ????????    ldx      [i5 - 72],o5
200    ????????    jmp      o5             <-- ra
201    ????????    nop
202
203    w/ sethi (mptr in dseg out of 13-bit simm range)
204
205    ????????    sethi    hi(0x2000),o5
206    ????????    sub      i5,o5,o5
207    ????????    ldx      [o5 - 72],o5
208    ????????    jmp      o5             <-- ra
209    ????????    nop
210
211    INVOKEVIRTUAL:
212
213    ????????    ldx      [o0 + 0},g2
214    ????????    ldx      [g2 + 0],o5
215    ????????    jmp      o5             <-- ra
216    ????????    nop
217
218    INVOKEINTERFACE:
219
220    ????????    ldx      [o0 + 0},g2
221    ????????    ldx      [g2 - 112],g2
222    ????????    ldx      [g2 + 24],o5
223    ????????    jmp      o5             <-- ra
224    ????????    nop
225
226 *******************************************************************************/
227
228 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
229 {
230         u4  mcode, mcode_sethi, mcode_masked;
231         s4  offset;
232         u1 *pa, *iptr;
233
234         /* go back to the location of a possible sethi (3 instruction before jump) */
235         /* note: ra is the address of the jump instruction on SPARC                */
236
237         mcode_sethi = *((u4 *) (ra - 3 * 4));
238
239         /* check for sethi instruction */
240
241         if (IS_SETHI(mcode_sethi)) {
242                 u4 mcode_sub, mcode_ldx;
243
244                 mcode_sub = *((u4 *) (ra - 2 * 4));
245                 mcode_ldx = *((u4 *) (ra - 1 * 4));
246
247                 /* make sure the sequence of instructions is a loadhi */
248                 if ((IS_SUB(mcode_sub)) && (IS_LDX_IMM(mcode_ldx)))
249                 {
250
251
252                 /* get 22-bit immediate of sethi instruction */
253
254                 offset = (s4) (mcode_sethi & 0x3fffff);
255                 offset = offset << 10;
256                 
257                 /* goto next instruction */
258                 
259                 /* make sure it's a sub instruction (pv - big_disp) */
260                 assert(IS_SUB(mcode_sub));
261                 offset = -offset;
262
263                 /* get displacement of load instruction */
264
265                 assert(IS_LDX_IMM(mcode_ldx));
266
267                 offset += decode_13bit_imm(mcode_ldx);
268                 
269                 pa = sfi->pv + offset;
270
271                 return pa;
272                 }
273         }
274
275         /* we didn't find a sethi, or it didn't belong to a loadhi */
276         /* check for simple (one-instruction) load */
277         iptr = ra - 1 * 4;
278         mcode = *((u4 *) iptr);
279
280         /* shift and mask rd */
281
282         mcode_masked = (mcode >> 13) & 0x060fff;
283         
284         /* get the offset from the instruction */
285
286         offset = decode_13bit_imm(mcode);
287
288         /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
289
290         if (mcode_masked == 0x0602c5) {
291                 /* in this case we use the passed method pointer */
292
293                 /* return NULL if no mptr was specified (used for replacement) */
294
295                 if (mptr == NULL)
296                         return NULL;
297
298                 pa = mptr + offset;
299
300         } else {
301                 /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
302
303                 assert(mcode_masked  == 0x0602fb);
304
305                 /* and get the final data segment address */
306
307                 pa = sfi->pv + offset;
308         }
309         
310
311         return pa;
312 }
313
314
315 /* md_cacheflush ***************************************************************
316
317    Calls the system's function to flush the instruction and data
318    cache.
319
320 *******************************************************************************/
321
322 void md_cacheflush(u1 *addr, s4 nbytes)
323 {
324         /* don't know yet */    
325 }
326
327
328 /* md_dcacheflush **************************************************************
329
330    Calls the system's function to flush the data cache.
331
332 *******************************************************************************/
333
334 void md_dcacheflush(u1 *addr, s4 nbytes)
335 {
336         /* XXX don't know yet */        
337         /* printf("md_dcacheflush\n"); */
338         __asm__ __volatile__ ( "membar 0x7F" : : : "memory" );
339 }
340
341
342 /* md_patch_replacement_point **************************************************
343
344    Patch the given replacement point.
345
346 *******************************************************************************/
347
348 #if defined(ENABLE_REPLACEMENT)
349 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
350 {
351         u4 mcode;
352
353         if (index < 0) {
354                 /* restore the patched-over instruction */
355                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
356         }
357         else {
358                 /* save the current machine code */
359                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
360
361                 /* build the machine code for the patch */
362                 assert(0); /* XXX build trap instruction below */
363                 mcode = 0;
364
365                 /* write the new machine code */
366                 *(u4*)(rp->pc) = (u4) mcode;
367         }
368         
369 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
370         {
371                 u1* u1ptr = rp->pc;
372                 DISASSINSTR(u1ptr);
373                 fflush(stdout);
374         }
375 #endif
376                         
377         /* flush instruction cache */
378     /* md_icacheflush(rp->pc,4); */
379 }
380 #endif /* defined(ENABLE_REPLACEMENT) */
381
382 /*
383  * These are local overrides for various environment variables in Emacs.
384  * Please do not remove this and leave it at the end of the file, where
385  * Emacs will automagically detect them.
386  * ---------------------------------------------------------------------
387  * Local variables:
388  * mode: c
389  * indent-tabs-mode: t
390  * c-basic-offset: 4
391  * tab-width: 4
392  * End:
393  * vim:noexpandtab:sw=4:ts=4:
394  */