Merged with new-trap-decoding branch at rev a792088a3f04 (branch closed).
[cacao.git] / src / vm / jit / i386 / md.c
1 /* src/vm/jit/i386/md.c - machine dependent i386 functions
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5    Copyright (C) 2009 Theobroma Systems Ltd.
6
7    This file is part of CACAO.
8
9    This program is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License as
11    published by the Free Software Foundation; either version 2, or (at
12    your option) any later version.
13
14    This program is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22    02110-1301, USA.
23
24 */
25
26
27 #include "config.h"
28
29 #include <assert.h>
30 #include <stdint.h>
31
32 #include "vm/types.h"
33
34 #include "vm/jit/i386/codegen.h"
35
36 #include "vm/global.h"
37 #include "vm/vm.hpp"
38
39 #include "vm/jit/asmpart.h"
40 #include "vm/jit/jit.hpp"
41 #include "vm/jit/trap.hpp"
42
43
44 /* md_init *********************************************************************
45
46    Do some machine dependent initialization.
47
48 *******************************************************************************/
49
50 void md_init(void)
51 {
52         (void) asm_md_init();
53 }
54
55
56 /* md_jit_method_patch_address *************************************************
57
58    Gets the patch address of the currently compiled method. The offset
59    is extracted from the load instruction(s) before the jump and added
60    to the right base address (PV or REG_METHODPTR).
61
62    INVOKESTATIC/SPECIAL:
63
64    b9 30 00 49 b7             mov    $0xb7490030,%ecx
65    ff d1                      call   *%ecx
66
67    INVOKEVIRTUAL:
68
69    8b 08                      mov    (%eax),%ecx
70    8b 91 00 00 00 00          mov    0x0(%ecx),%edx
71    ff d2                      call   *%edx
72
73    INVOKEINTERFACE:
74
75    8b 08                      mov    (%eax),%ecx
76    8b 89 00 00 00 00          mov    0x0(%ecx),%ecx
77    8b 91 00 00 00 00          mov    0x0(%ecx),%edx
78    ff d2                      call   *%edx
79
80 *******************************************************************************/
81
82 void *md_jit_method_patch_address(void *pv, void *ra, void *mptr)
83 {
84         uint8_t  *pc;
85         uint16_t  opcode;
86         int32_t   disp;
87         void     *pa;                                            /* patch address */
88
89         /* go back to the actual call instruction (2-bytes) */
90
91         pc = ((uint8_t *) ra) - 2;
92
93         /* Get the opcode of the call. */
94
95         opcode = *((uint16_t *) pc);
96
97         /* check for the different calls */
98
99         switch (opcode) {
100         case 0xd1ff:
101                 /* INVOKESTATIC/SPECIAL */
102
103                 /* Patch address is 4-bytes before the call instruction. */
104
105                 pa = pc - 4;
106                 break;
107
108         case 0xd2ff:
109                 /* INVOKEVIRTUAL/INTERFACE */
110
111                 /* Return NULL if no mptr was specified (used for
112                    replacement). */
113
114                 if (mptr == NULL)
115                         return NULL;
116
117                 /* Get the displacement from the instruction (the displacement
118                    address is 4-bytes before the call instruction). */
119
120                 disp = *((int32_t *) (pc - 4));
121
122                 /* Add the displacement to the method pointer. */
123
124                 pa = ((uint8_t *) mptr) + disp;
125                 break;
126
127         default:
128                 vm_abort_disassemble(pc, 1, "md_jit_method_patch_address: unknown instruction %x", opcode);
129                 return NULL;
130         }
131
132         return pa;
133 }
134
135
136 /**
137  * Decode the trap instruction at the given PC.
138  *
139  * @param trp information about trap to be filled
140  * @param sig signal number
141  * @param xpc exception PC
142  * @param es execution state of the machine
143  * @return true if trap was decoded successfully, false otherwise.
144  */
145 bool md_trap_decode(trapinfo_t* trp, int sig, void* _xpc, executionstate_t* es)
146 {
147         uint8_t* xpc = (uint8_t*) _xpc;
148
149         switch (sig) {
150         case TRAP_SIGFPE:
151                 // This is an ArithmeticException.
152                 trp->type  = TRAP_ArithmeticException;
153                 trp->value = 0;
154                 return true;
155
156         case TRAP_SIGILL:
157                 // Check for valid trap instruction.
158                 if (patcher_is_valid_trap_instruction_at(xpc)) {
159                         trp->type  = TRAP_PATCHER;
160                         trp->value = 0;
161                         return true;
162                 }
163                 return false;
164
165         case TRAP_SIGSEGV:
166         {
167                 // Get exception-throwing instruction.
168                 uint8_t opc = M_ALD_MEM_GET_OPC(xpc);
169                 uint8_t mod = M_ALD_MEM_GET_MOD(xpc);
170                 uint8_t rm  = M_ALD_MEM_GET_RM(xpc);
171
172                 // Check for hardware exception, for values
173                 // see emit_mov_mem_reg and emit_mem.
174                 if ((opc == 0x8b) && (mod == 0) && (rm == 5)) {
175                         int32_t d    = M_ALD_MEM_GET_REG(xpc);
176                         int32_t disp = M_ALD_MEM_GET_DISP(xpc);
177
178                         // We use the exception type as load displacement.
179                         trp->type  = disp;
180                         trp->value = es->intregs[d];
181                         return true;
182                 }
183
184                 // Default case is a normal NullPointerException.
185                 else {
186                         trp->type  = TRAP_NullPointerException;
187                         trp->value = 0;
188                         return true;
189                 }
190         }
191
192         default:
193                 return false;
194         }
195 }
196
197
198 /* md_patch_replacement_point **************************************************
199
200    Patch the given replacement point.
201
202 *******************************************************************************/
203
204 #if defined(ENABLE_REPLACEMENT)
205 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
206 {
207         u2 mcode;
208
209         if (revert) {
210                 /* write saved machine code */
211                 *(u2*)(pc) = *(u2*)(savedmcode);
212         }
213         else {
214                 /* save the current machine code */
215                 *(u2*)(savedmcode) = *(u2*)(pc);
216
217                 /* build the machine code for the patch */
218                 mcode = 0x0b0f;
219
220                 /* write new machine code */
221                 *(u2*)(pc) = mcode;
222         }
223
224     /* XXX if required asm_cacheflush(pc,8); */
225 }
226 #endif /* defined(ENABLE_REPLACEMENT) */
227
228 /*
229  * These are local overrides for various environment variables in Emacs.
230  * Please do not remove this and leave it at the end of the file, where
231  * Emacs will automagically detect them.
232  * ---------------------------------------------------------------------
233  * Local variables:
234  * mode: c
235  * indent-tabs-mode: t
236  * c-basic-offset: 4
237  * tab-width: 4
238  * End:
239  * vim:noexpandtab:sw=4:ts=4:
240  */