Merge from subtype.
[cacao.git] / src / vm / jit / sparc64 / md.c
1 /* src/vm/jit/sparc64/md.c - machine dependent SPARC64 functions
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30
31 #include "vm/types.h"
32
33 #include "vm/jit/sparc64/md-abi.h"
34
35 #include "vm/jit/asmpart.h"
36 #include "vm/jit/codegen-common.hpp"
37 #include "vm/jit/jit.hpp"
38
39
40 /* assembler function prototypes **********************************************/
41 void asm_store_fp_state_reg(u8 *mem);
42 void asm_load_fp_state_reg(u8 *mem);
43
44
45 /* NOP is defined as a SETHI instruction with rd and imm. set to zero */
46 /* therefore we check if the 22-bit immediate is zero */
47 #define IS_SETHI(instr) \
48         (((instr & 0xc1c00000)  == 0x01000000) \
49         && ((instr & 0x3fffff) != 0x0))
50         
51 #define IS_LDX_IMM(instr) \
52         (((instr >> 13) & 0x60fc1) == 0x602c1)
53         
54 #define IS_SUB(instr) \
55         (((instr >> 13) & 0x60fc0) == 0x40100)
56
57 inline s2 decode_13bit_imm(u4 instr) {
58         s2 imm;
59
60         /* mask everything else in the instruction */
61         imm = instr & 0x00001fff;
62
63         /* sign extend 13-bit to 16-bit */
64         imm <<= 3;
65         imm >>= 3;
66
67         return imm;
68 }
69
70 /* md_init *********************************************************************
71
72    Do some machine dependent initialization.
73
74 *******************************************************************************/
75
76 void md_init(void)
77 {
78         /* do nothing */
79 }
80
81
82 /* md_jit_method_patch_address *************************************************
83
84    Gets the patch address of the currently compiled method. The offset
85    is extracted from the load instruction(s) before the jump and added
86    to the right base address (PV or REG_METHODPTR).
87
88    INVOKESTATIC/SPECIAL:
89
90    ????????    ldx      [i5 - 72],o5
91    ????????    jmp      o5             <-- ra
92    ????????    nop
93
94    w/ sethi (mptr in dseg out of 13-bit simm range)
95
96    ????????    sethi    hi(0x2000),o5
97    ????????    sub      i5,o5,o5
98    ????????    ldx      [o5 - 72],o5
99    ????????    jmp      o5             <-- ra
100    ????????    nop
101
102    INVOKEVIRTUAL:
103
104    ????????    ldx      [o0 + 0},g2
105    ????????    ldx      [g2 + 0],o5
106    ????????    jmp      o5             <-- ra
107    ????????    nop
108
109    INVOKEINTERFACE:
110
111    ????????    ldx      [o0 + 0},g2
112    ????????    ldx      [g2 - 112],g2
113    ????????    ldx      [g2 + 24],o5
114    ????????    jmp      o5             <-- ra
115    ????????    nop
116
117 *******************************************************************************/
118
119 void *md_jit_method_patch_address(void *pv, void *ra, void *mptr)
120 {
121         uint32_t *pc;
122         uint32_t  mcode, mcode_sethi, mcode_masked;
123         int32_t   disp;
124         uint8_t  *iptr;
125         void     *pa;
126
127         /* Go back to the location of a possible sethi (3 instruction
128            before jump). */
129
130         pc = ((uint32_t *) ra) - 3;
131
132         /* note: ra is the address of the jump instruction on SPARC */
133
134         mcode_sethi = pc[0];
135
136         /* check for sethi instruction */
137
138         if (IS_SETHI(mcode_sethi)) {
139                 u4 mcode_sub, mcode_ldx;
140
141                 mcode_sub = pc[1];
142                 mcode_ldx = pc[2];
143
144                 /* make sure the sequence of instructions is a loadhi */
145                 if ((IS_SUB(mcode_sub)) && (IS_LDX_IMM(mcode_ldx)))
146                 {
147
148
149                 /* get 22-bit immediate of sethi instruction */
150
151                 disp = (int32_t) (mcode_sethi & 0x3fffff);
152                 disp = disp << 10;
153                 
154                 /* goto next instruction */
155                 
156                 /* make sure it's a sub instruction (pv - big_disp) */
157                 assert(IS_SUB(mcode_sub));
158                 disp = -disp;
159
160                 /* get displacement of load instruction */
161
162                 assert(IS_LDX_IMM(mcode_ldx));
163
164                 disp += decode_13bit_imm(mcode_ldx);
165                 
166                 pa = ((uint8_t *) pv) + disp;
167
168                 return pa;
169                 }
170         }
171
172         /* we didn't find a sethi, or it didn't belong to a loadhi */
173         /* check for simple (one-instruction) load */
174
175         mcode = pc[2];
176
177         /* shift and mask rd */
178
179         mcode_masked = (mcode >> 13) & 0x060fff;
180         
181         /* get the offset from the instruction */
182
183         disp = decode_13bit_imm(mcode);
184
185         /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
186
187         if (mcode_masked == 0x0602c5) {
188                 /* in this case we use the passed method pointer */
189
190                 /* return NULL if no mptr was specified (used for replacement) */
191
192                 if (mptr == NULL)
193                         return NULL;
194
195                 pa = ((uint8_t *) mptr) + disp;
196
197         } else {
198                 /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
199
200                 assert(mcode_masked  == 0x0602fb);
201
202                 /* and get the final data segment address */
203
204                 pa = ((uint8_t *) pv) + disp;
205         }
206
207         return pa;
208 }
209
210
211 /* md_patch_replacement_point **************************************************
212
213    Patch the given replacement point.
214
215 *******************************************************************************/
216
217 #if defined(ENABLE_REPLACEMENT)
218 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
219 {
220         u4 mcode;
221
222         if (revert) {
223                 /* restore the patched-over instruction */
224                 *(u4*)(pc) = *(u4*)(savedmcode);
225         }
226         else {
227                 /* save the current machine code */
228                 *(u4*)(savedmcode) = *(u4*)(pc);
229
230                 /* build the machine code for the patch */
231                 assert(0); /* XXX build trap instruction below */
232                 mcode = 0;
233
234                 /* write the new machine code */
235                 *(u4*)(pc) = (u4) mcode;
236         }
237
238         /* flush instruction cache */
239     /* md_icacheflush(pc,4); */
240 }
241 #endif /* defined(ENABLE_REPLACEMENT) */
242
243 /*
244  * These are local overrides for various environment variables in Emacs.
245  * Please do not remove this and leave it at the end of the file, where
246  * Emacs will automagically detect them.
247  * ---------------------------------------------------------------------
248  * Local variables:
249  * mode: c
250  * indent-tabs-mode: t
251  * c-basic-offset: 4
252  * tab-width: 4
253  * End:
254  * vim:noexpandtab:sw=4:ts=4:
255  */