639c1cfd5226dd3da572c34d25736eb09e148d4c
[cacao.git] / src / vm / jit / mips / md.c
1 /* src/vm/jit/mips/md.c - machine dependent MIPS functions
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008, 2009
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/mips/md.h"
34
35 #include "vm/global.h"
36 #include "vm/vm.hpp"
37
38 #include "vm/jit/jit.hpp"
39
40
41 /* md_jit_method_patch_address *************************************************
42
43    Gets the patch address of the currently compiled method. The offset
44    is extracted from the load instruction(s) before the jump and added
45    to the right base address (PV or REG_METHODPTR).
46
47    INVOKESTATIC/SPECIAL:
48
49    dfdeffb8    ld       s8,-72(s8)
50    03c0f809    jalr     s8
51    00000000    nop
52
53    INVOKEVIRTUAL:
54
55    dc990000    ld       t9,0(a0)
56    df3e0000    ld       s8,0(t9)
57    03c0f809    jalr     s8
58    00000000    nop
59
60    INVOKEINTERFACE:
61
62    dc990000    ld       t9,0(a0)
63    df39ff90    ld       t9,-112(t9)
64    df3e0018    ld       s8,24(t9)
65    03c0f809    jalr     s8
66    00000000    nop
67
68 *******************************************************************************/
69
70 void *md_jit_method_patch_address(void *pv, void *ra, void *mptr)
71 {
72         uint32_t *pc;
73         uint32_t  mcode;
74         int32_t   offset;
75         void     *pa;
76
77         /* go back to the actual load instruction (3 instructions on MIPS) */
78
79         pc = ((uint32_t *) ra) - 3;
80
81         /* get first instruction word on current PC */
82
83         mcode = pc[0];
84
85         /* check if we have 2 instructions (lui) */
86
87         if ((mcode >> 16) == 0x3c19) {
88                 /* XXX write a regression for this */
89                 assert(0);
90
91                 /* get displacement of first instruction (lui) */
92
93                 offset = (int32_t) (mcode << 16);
94
95                 /* get displacement of second instruction (daddiu) */
96
97                 mcode = pc[1];
98
99                 assert((mcode >> 16) != 0x6739);
100
101                 offset += (int16_t) (mcode & 0x0000ffff);
102
103                 pa = NULL;
104         }
105         else {
106                 /* get the offset from the instruction */
107
108                 offset = (int16_t) (mcode & 0x0000ffff);
109
110                 /* check for call with REG_METHODPTR: ld s8,x(t9) */
111
112 #if SIZEOF_VOID_P == 8
113                 if ((mcode >> 16) == 0xdf3e) {
114 #else
115                 if ((mcode >> 16) == 0x8f3e) {
116 #endif
117                         /* in this case we use the passed method pointer */
118
119                         /* return NULL if no mptr was specified (used for replacement) */
120
121                         if (mptr == NULL)
122                                 return NULL;
123
124                         pa = ((uint8_t *) mptr) + offset;
125                 }
126                 else {
127                         /* in the normal case we check for a `ld s8,x(s8)' instruction */
128
129 #if SIZEOF_VOID_P == 8
130                         assert((mcode >> 16) == 0xdfde);
131 #else
132                         assert((mcode >> 16) == 0x8fde);
133 #endif
134
135                         /* and get the final data segment address */
136
137                         pa = ((uint8_t *) pv) + offset;
138                 }
139         }
140
141         return pa;
142 }
143
144
145 /**
146  * Decode the trap instruction at the given PC.
147  *
148  * @param trp information about trap to be filled
149  * @param sig signal number
150  * @param xpc exception PC
151  * @param es execution state of the machine
152  * @return true if trap was decoded successfully, false otherwise.
153  */
154 bool md_trap_decode(trapinfo_t* trp, int sig, void* xpc, executionstate_t* es)
155 {
156     // Get the exception-throwing instruction.
157     uint32_t mcode = *((uint32_t*) xpc);
158
159     switch (sig) {
160     case TRAP_SIGILL:
161         // Check for valid trap instruction.
162         // TODO Check the whole instruction.
163         if (mcode == 0xec000000) {
164             trp->type  = TRAP_PATCHER;
165             trp->value = 0;
166             return true;
167         }
168         return false;
169
170     case TRAP_SIGSEGV:
171     {
172         // Retrieve base address of instruction.
173         int32_t   s1   = M_ITYPE_GET_RS(mcode);
174         uintptr_t addr = es->intregs[s1];
175
176         // Check for special-load.
177         if (s1 == REG_ZERO) {
178             int32_t d    = M_ITYPE_GET_RT(mcode);
179             int32_t disp = M_ITYPE_GET_IMM(mcode);
180
181             // We use the exception type as load displacement.
182             trp->type  = disp;
183             trp->value = es->intregs[d];
184             return true;
185         }
186
187         // Check for implicit NullPointerException.
188         if (addr == 0) {
189             trp->type  = TRAP_NullPointerException;
190             trp->value = 0;
191             return true;
192         }
193
194         return false;
195     }
196
197     default:
198         return false;
199     }
200 }
201
202
203 /* md_patch_replacement_point **************************************************
204
205    Patch the given replacement point.
206
207 *******************************************************************************/
208
209 #if defined(ENABLE_REPLACEMENT)
210 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
211 {
212         union {
213                 u8 both;
214                 u4 words[2];
215         } mcode;
216
217         if (revert) {
218                 /* restore the patched-over instruction */
219                 *(u8*)(pc) = *(u8*)(savedmcode);
220         }
221         else {
222                 /* save the current machine code */
223                 *(u8*)(savedmcode) = *(u8*)(pc);
224
225                 /* build the machine code for the patch */
226                 assert(0); /* XXX build trap instruction below */
227                 mcode.both = 0;
228
229                 /* write the new machine code */
230                 *(u8*)(pc) = mcode.both;
231         }
232
233         /* flush instruction cache */
234     md_icacheflush(pc,2*4);
235 }
236 #endif /* defined(ENABLE_REPLACEMENT) */
237
238
239 /*
240  * These are local overrides for various environment variables in Emacs.
241  * Please do not remove this and leave it at the end of the file, where
242  * Emacs will automagically detect them.
243  * ---------------------------------------------------------------------
244  * Local variables:
245  * mode: c
246  * indent-tabs-mode: t
247  * c-basic-offset: 4
248  * tab-width: 4
249  * End:
250  * vim:noexpandtab:sw=4:ts=4:
251  */