* src/vm/jit/x86_64/asmpart.S (asm_abstractmethoderror): Keep stack aligned.
[cacao.git] / src / vm / jit / x86_64 / md.c
1 /* src/vm/jit/x86_64/md.c - machine dependent x86_64 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 #include <stdlib.h>
32
33 #include "vm/jit/x86_64/codegen.h"
34 #include "vm/jit/x86_64/md-abi.h"
35
36 #include "vm/vm.hpp"
37
38 #include "vm/jit/codegen-common.hpp"
39 #include "vm/jit/executionstate.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         /* nothing to do */
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    4d 8b 15 e2 fe ff ff             mov    -286(%rip),%r10
65    49 ff d2                         rex64Z callq  *%r10
66
67    INVOKEVIRTUAL:
68
69    4c 8b 17                         mov    (%rdi),%r10
70    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
71    48 ff d3                         rex64 callq  *%rax
72
73    INVOKEINTERFACE:
74
75    4c 8b 17                         mov    (%rdi),%r10
76    4d 8b 92 00 00 00 00             mov    0x0(%r10),%r10
77    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
78    48 ff d3                         rex64 callq  *%r11
79
80 *******************************************************************************/
81
82 void *md_jit_method_patch_address(void *pv, void *ra, void *mptr)
83 {
84         uint8_t *pc;
85         uint8_t  mcode;
86         int32_t  offset;
87         void    *pa;                        /* patch address                      */
88
89         /* go back to the actual call instruction (3-bytes) */
90
91         pc = ((uint8_t *) ra) - 3;
92
93         /* get the last byte of the call */
94
95         mcode = pc[2];
96
97         /* check for the different calls */
98
99         if (mcode == 0xd2) {
100                 /* INVOKESTATIC/SPECIAL */
101
102                 /* Get the offset from the instruction (the offset address is
103                    4-bytes before the call instruction). */
104
105                 offset = *((int32_t *) (pc - 4));
106
107                 /* add the offset to the return address (IP-relative addressing) */
108
109                 pa = pc + offset;
110         }
111         else if (mcode == 0xd3) {
112                 /* INVOKEVIRTUAL/INTERFACE */
113
114                 /* return NULL if no mptr was specified (used for replacement) */
115
116                 if (mptr == NULL)
117                         return NULL;
118
119                 /* Get the offset from the instruction (the offset address is
120                    4-bytes before the call instruction). */
121
122                 offset = *((int32_t *) (pc - 4));
123
124                 /* add the offset to the method pointer */
125
126                 pa = ((uint8_t *) mptr) + offset;
127         }
128         else {
129                 /* catch any problems */
130
131                 vm_abort("md_jit_method_patch_address: unknown instruction %x", mcode);
132
133                 /* keep compiler happy */
134
135                 pa = NULL;
136         }
137
138         return pa;
139 }
140
141
142 /**
143  * Decode the trap instruction at the given PC.
144  *
145  * @param trp information about trap to be filled
146  * @param sig signal number
147  * @param xpc exception PC
148  * @param es execution state of the machine
149  * @return true if trap was decoded successfully, false otherwise.
150  */
151 bool md_trap_decode(trapinfo_t* trp, int sig, void* _xpc, executionstate_t* es)
152 {
153         uint8_t* xpc = (uint8_t*) _xpc;
154
155 #if 0
156         // Check for StackOverflowException.
157         threads_check_stackoverflow(sp);
158 #endif
159
160         switch (sig) {
161         case TRAP_SIGFPE:
162                 // Check for ArithmeticException.
163                 trp->type  = TRAP_ArithmeticException;
164                 trp->value = 0;
165                 return true;
166
167         case TRAP_SIGILL:
168                 // Check for valid trap instruction.
169                 if (patcher_is_valid_trap_instruction_at(xpc)) {
170                         trp->type  = TRAP_PATCHER;
171                         trp->value = 0;
172                         return true;
173                 }
174                 return false;
175
176         case TRAP_SIGSEGV:
177         {
178                 // Get exception-throwing instruction.
179                 uint8_t opc = M_ALD_MEM_GET_OPC(xpc);
180                 uint8_t mod = M_ALD_MEM_GET_MOD(xpc);
181                 uint8_t rm  = M_ALD_MEM_GET_RM(xpc);
182
183                 // Check for hardware exception, for values
184                 // see emit_mov_mem_reg and emit_mem.
185                 if ((opc == 0x8b) && (mod == 0) && (rm == 4)) {
186                         int32_t d    = M_ALD_MEM_GET_REG(xpc);
187                         int32_t disp = M_ALD_MEM_GET_DISP(xpc);
188
189                         // We use the exception type as load displacement.
190                         trp->type  = disp;
191                         trp->value = es->intregs[d];
192                         return true;
193                 }
194
195                 // Default case is a normal NullPointerException.
196                 else {
197                         trp->type  = TRAP_NullPointerException;
198                         trp->value = 0;
199                         return true;
200                 }
201         }
202         
203         default:
204                 return false;
205         }
206 }
207
208
209 /* md_patch_replacement_point **************************************************
210
211    Patch the given replacement point.
212
213 *******************************************************************************/
214
215 #if defined(ENABLE_REPLACEMENT)
216 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
217 {
218         u2 mcode;
219
220         if (revert) {
221                 /* write saved machine code */
222                 *(u2*)(pc) = *(u2*)(savedmcode);
223         }
224         else {
225                 /* save the current machine code */
226                 *(u2*)(savedmcode) = *(u2*)(pc);
227
228                 /* build the machine code for the patch */
229                 mcode = 0x0b0f;
230
231                 /* write new machine code */
232                 *(u2*)(pc) = (u2) mcode;
233         }
234
235     /* XXX if required asm_cacheflush(pc,8); */
236 }
237 #endif /* defined(ENABLE_REPLACEMENT) */
238
239
240 /*
241  * These are local overrides for various environment variables in Emacs.
242  * Please do not remove this and leave it at the end of the file, where
243  * Emacs will automagically detect them.
244  * ---------------------------------------------------------------------
245  * Local variables:
246  * mode: c
247  * indent-tabs-mode: t
248  * c-basic-offset: 4
249  * tab-width: 4
250  * End:
251  * vim:noexpandtab:sw=4:ts=4:
252  */