Line data Source code
1 : /* src/vm/jit/x86_64/md.cpp - machine dependent x86_64 functions
2 :
3 : Copyright (C) 1996-2013
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 <cassert>
30 : #include <cstdlib>
31 : #include <stdint.h>
32 :
33 : #include "vm/jit/x86_64/codegen.hpp"
34 : #include "vm/jit/x86_64/md-abi.hpp"
35 :
36 : #include "vm/vm.hpp"
37 :
38 : #include "vm/jit/codegen-common.hpp"
39 : #include "vm/jit/executionstate.hpp"
40 : #include "vm/jit/patcher-common.hpp"
41 : #include "vm/jit/trap.hpp"
42 :
43 :
44 : /* md_init *********************************************************************
45 :
46 : Do some machine dependent initialization.
47 :
48 : *******************************************************************************/
49 :
50 163 : void md_init(void)
51 : {
52 : /* nothing to do */
53 163 : }
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 126219 : 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 126219 : pc = ((uint8_t *) ra) - 3;
92 :
93 : /* get the last byte of the call */
94 :
95 126219 : mcode = pc[2];
96 :
97 : /* check for the different calls */
98 :
99 126219 : 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 91001 : offset = *((int32_t *) (pc - 4));
106 :
107 : /* add the offset to the return address (IP-relative addressing) */
108 :
109 91001 : pa = pc + offset;
110 : }
111 35218 : else if (mcode == 0xd3) {
112 : /* INVOKEVIRTUAL/INTERFACE */
113 :
114 : /* return NULL if no mptr was specified (used for replacement) */
115 :
116 35218 : if (mptr == NULL)
117 0 : return NULL;
118 :
119 : /* Get the offset from the instruction (the offset address is
120 : 4-bytes before the call instruction). */
121 :
122 35218 : offset = *((int32_t *) (pc - 4));
123 :
124 : /* add the offset to the method pointer */
125 :
126 35218 : pa = ((uint8_t *) mptr) + offset;
127 : }
128 : else {
129 : /* catch any problems */
130 :
131 0 : vm_abort("md_jit_method_patch_address: unknown instruction %x", mcode);
132 :
133 : /* keep compiler happy */
134 :
135 0 : pa = NULL;
136 : }
137 :
138 126219 : 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 218378 : bool md_trap_decode(trapinfo_t* trp, int sig, void* _xpc, executionstate_t* es)
152 : {
153 218378 : uint8_t* xpc = (uint8_t*) _xpc;
154 :
155 : #if 0
156 : // Check for StackOverflowException.
157 : threads_check_stackoverflow(sp);
158 : #endif
159 :
160 218378 : switch (sig) {
161 : case TRAP_SIGFPE:
162 : // Check for ArithmeticException.
163 8 : trp->type = TRAP_ArithmeticException;
164 8 : trp->value = 0;
165 8 : return true;
166 :
167 : case TRAP_SIGILL:
168 : // Check for valid trap instruction.
169 71147 : if (patcher_is_valid_trap_instruction_at(xpc)) {
170 71146 : trp->type = TRAP_PATCHER;
171 71146 : trp->value = 0;
172 71146 : return true;
173 : }
174 1 : return false;
175 :
176 : case TRAP_SIGSEGV:
177 : {
178 : // Get exception-throwing instruction.
179 147223 : uint8_t opc = M_ALD_MEM_GET_OPC(xpc);
180 147223 : uint8_t mod = M_ALD_MEM_GET_MOD(xpc);
181 147223 : 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 147223 : if ((opc == 0x8b) && (mod == 0) && (rm == 4)) {
186 147201 : int32_t d = M_ALD_MEM_GET_REG(xpc);
187 147201 : int32_t disp = M_ALD_MEM_GET_DISP(xpc);
188 :
189 : // We use the exception type as load displacement.
190 147201 : trp->type = disp;
191 147201 : trp->value = es->intregs[d];
192 147201 : return true;
193 : }
194 :
195 : // Default case is a normal NullPointerException.
196 : else {
197 22 : trp->type = TRAP_NullPointerException;
198 22 : trp->value = 0;
199 22 : return true;
200 : }
201 : }
202 :
203 : default:
204 0 : 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 : */
|