Merged revisions 7766-7796 via svnmerge from
[cacao.git] / src / vm / jit / sparc64 / md.c
1 /* src/vm/jit/alpha/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         u4  mcode_masked;
155         s4  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 a sethi insruction */
163         if (IS_SETHI(mcode)) {
164                 s4 xor_imm;
165                                 
166                 /* get 22-bit immediate of sethi instruction */
167                 offset = (s4) (mcode & 0x3fffff);
168                 offset = offset << 10;
169                 
170                 /* now the xor */
171                 mcode = *((u4 *) (ra+12) );
172                 xor_imm = decode_13bit_imm(mcode);
173                 
174                 offset ^= xor_imm;       
175         }
176         else {
177                 u4 mcode_masked;
178                 
179                 mcode_masked = SHIFT_AND_MASK(mcode);
180
181                 assert(mcode_masked == 0x40001);
182
183                 /* mask and extend the negative sign for the 13 bit immediate */
184                 offset = decode_13bit_imm(mcode);
185         }
186         
187         pv += offset;
188
189         return pv;
190 }
191
192 /* md_get_method_patch_address *************************************************
193
194    Gets the patch address of the currently compiled method. The offset
195    is extracted from the load instruction(s) before the jump and added
196    to the right base address (PV or REG_METHODPTR).
197
198    INVOKESTATIC/SPECIAL:
199
200    dfdeffb8    ldx      [i5 - 72],o5
201    03c0f809    jmp      o5
202    00000000    nop
203
204    INVOKEVIRTUAL:
205
206    dc990000    ld       t9,0(a0)
207    df3e0000    ld       [g2 + 0],o5
208    03c0f809    jmp      o5
209    00000000    nop
210
211    INVOKEINTERFACE:
212
213    dc990000    ld       t9,0(a0)
214    df39ff90    ld       [g2 - 112],g2
215    df3e0018    ld       [g2 + 24],o5
216    03c0f809    jmp      o5
217    00000000    nop
218
219 *******************************************************************************/
220
221 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
222 {
223         u4  mcode, mcode_masked;
224         s4  offset;
225         u1 *pa, *iptr;
226
227         /* go back to the location of a possible sethi (3 instruction before jump) */
228         /* note: ra is the address of the jump instruction on SPARC                */
229         iptr = ra - 3 * 4;
230
231         /* get first instruction word on current PC */
232
233         mcode = *((u4 *) iptr);
234
235         /* check for sethi instruction */
236
237         if (IS_SETHI(mcode)) {
238                 /* XXX write a regression for this */
239
240                 /* get 22-bit immediate of sethi instruction */
241
242                 offset = (s4) (mcode & 0x3fffff);
243                 offset = offset << 10;
244                 
245                 /* goto next instruction */
246                 iptr += 4;
247                 mcode = *((u4 *) iptr);
248                 
249                 /* make sure it's a sub instruction (pv - big_disp) */
250                 assert(IS_SUB(mcode));
251                 offset = -offset;
252
253                 /* get displacement of load instruction */
254
255                 mcode = *((u4 *) (ra - 1 * 4));
256                 assert(IS_LDX_IMM(mcode));
257
258                 offset += decode_13bit_imm(mcode);
259                 
260                 pa = sfi->pv + offset;
261
262                 return pa;
263         }
264
265
266         /* simple (one-instruction) load */
267         iptr = ra - 1 * 4;
268         mcode = *((u4 *) iptr);
269
270         /* shift and mask rd */
271
272         mcode_masked = (mcode >> 13) & 0x060fff;
273         
274         /* get the offset from the instruction */
275
276         offset = decode_13bit_imm(mcode);
277
278         /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
279
280         if (mcode_masked == 0x0602c5) {
281                 /* in this case we use the passed method pointer */
282
283                 /* return NULL if no mptr was specified (used for replacement) */
284
285                 if (mptr == NULL)
286                         return NULL;
287
288                 pa = mptr + offset;
289
290         } else {
291                 /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
292
293                 assert(mcode_masked  == 0x0602fb);
294
295                 /* and get the final data segment address */
296
297                 pa = sfi->pv + offset;
298         }
299         
300
301         return pa;
302 }
303
304
305 /* md_cacheflush ***************************************************************
306
307    Calls the system's function to flush the instruction and data
308    cache.
309
310 *******************************************************************************/
311
312 void md_cacheflush(u1 *addr, s4 nbytes)
313 {
314         /* don't know yet */    
315 }
316
317
318 /* md_dcacheflush **************************************************************
319
320    Calls the system's function to flush the data cache.
321
322 *******************************************************************************/
323
324 void md_dcacheflush(u1 *addr, s4 nbytes)
325 {
326         /* XXX don't know yet */        
327 }
328
329
330 /* md_patch_replacement_point **************************************************
331
332    Patch the given replacement point.
333
334 *******************************************************************************/
335
336 #if defined(ENABLE_REPLACEMENT)
337 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
338 {
339         s4 disp;
340         u4 mcode;
341         
342         assert(0);
343
344         if (index < 0) {
345                 /* restore the patched-over instruction */
346                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
347         }
348         else {
349                 /* save the current machine code */
350                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
351
352                 /* build the machine code for the patch */
353                 disp = ((u4*)code->replacementstubs - (u4*)rp->pc)
354                            + index * REPLACEMENT_STUB_SIZE
355                            - 1;
356
357                 mcode = (((s4)(0x00))<<30) | ((0)<<29) | ((0x8)<<25) | (0x1<<22) | (0<<20)
358                           | (1 << 19 ) | ((disp) & 0x007ffff);
359
360                 /* write the new machine code */
361                 *(u4*)(rp->pc) = (u4) mcode;
362         }
363         
364 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
365         {
366                 u1* u1ptr = rp->pc;
367                 DISASSINSTR(u1ptr);
368                 fflush(stdout);
369         }
370 #endif
371                         
372         /* flush instruction cache */
373     /* md_icacheflush(rp->pc,4); */
374 }
375 #endif /* defined(ENABLE_REPLACEMENT) */
376
377 /*
378  * These are local overrides for various environment variables in Emacs.
379  * Please do not remove this and leave it at the end of the file, where
380  * Emacs will automagically detect them.
381  * ---------------------------------------------------------------------
382  * Local variables:
383  * mode: c
384  * indent-tabs-mode: t
385  * c-basic-offset: 4
386  * tab-width: 4
387  * End:
388  * vim:noexpandtab:sw=4:ts=4:
389  */