CACAO
md.cpp
Go to the documentation of this file.
1 /* src/vm/jit/s390/md.cpp - machine dependent s390 Linux functions
2 
3  Copyright (C) 1996-2013
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 
29 #include <cassert>
30 #include <stdint.h>
31 
32 #include "vm/types.hpp"
33 
34 #include "vm/jit/s390/codegen.hpp"
35 #include "vm/jit/s390/md-abi.hpp"
36 
37 #include "vm/exceptions.hpp"
38 #include "vm/vm.hpp"
39 
40 #include "vm/jit/abi.hpp"
41 #include "vm/jit/code.hpp"
44 #include "vm/jit/jit.hpp"
45 #include "vm/jit/methodtree.hpp"
47 #include "vm/jit/trap.hpp"
48 
49 /* md_init *********************************************************************
50 
51  Do some machine dependent initialization.
52 
53 *******************************************************************************/
54 
55 void md_init(void)
56 {
57 }
58 
59 /**
60  * NullPointerException signal handler for hardware null pointer check.
61  */
62 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
63 {
64  ucontext_t* _uc = (ucontext_t *) _p;
65  mcontext_t* _mc = &_uc->uc_mcontext;
66 
67  void* xpc = (u1 *) _mc->psw.addr;
68 
69  // Handle the trap.
70  trap_handle(TRAP_SIGSEGV, xpc, _p);
71 }
72 
73 /**
74  * Illegal Instruction signal handler for hardware exception checks.
75  */
76 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
77 {
78  ucontext_t* _uc = (ucontext_t *) _p;
79  mcontext_t* _mc = &_uc->uc_mcontext;
80 
81  void* xpc = siginfo->si_addr;
82 
83  // Handle the trap.
84  trap_handle(TRAP_SIGILL, xpc, _p);
85 }
86 
87 /* md_signal_handler_sigfpe ****************************************************
88 
89  ArithmeticException signal handler for hardware divide by zero
90  check.
91 
92 *******************************************************************************/
93 
94 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
95 {
96  ucontext_t* _uc = (ucontext_t *) _p;
97  mcontext_t* _mc = &_uc->uc_mcontext;
98 
99  void* xpc = siginfo->si_addr;
100 
101  if (N_RR_GET_OPC((uint8_t*) xpc) == OPC_DR) { /* DR */
102 
103  int r1 = N_RR_GET_REG1((uint8_t*) xpc);
104  int r2 = N_RR_GET_REG2((uint8_t*) xpc);
105 
106  if (
107  (_mc->gregs[r1] == 0xFFFFFFFF) &&
108  (_mc->gregs[r1 + 1] == 0x80000000) &&
109  (_mc->gregs[r2] == 0xFFFFFFFF)
110  ) {
111  /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
112  /* next instruction */
113  u1 *pc = (u1 *)_mc->psw.addr;
114  /* remainder */
115  _mc->gregs[r1] = 0;
116  /* quotient */
117  _mc->gregs[r1 + 1] = 0x80000000;
118  /* continue at next instruction */
119  _mc->psw.addr = (ptrint) pc;
120 
121  return;
122  }
123  }
124 
125  // Handle the trap.
126  trap_handle(TRAP_SIGFPE, xpc, _p);
127 }
128 
129 
130 /* md_signal_handler_sigusr2 ***************************************************
131 
132  Signal handler for profiling sampling.
133 
134 *******************************************************************************/
135 
136 #if defined(ENABLE_THREADS)
137 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
138 {
139  threadobject *t;
140  ucontext_t *_uc;
141  mcontext_t *_mc;
142  u1 *pc;
143 
144  t = THREADOBJECT;
145 
146  _uc = (ucontext_t *) _p;
147  _mc = &_uc->uc_mcontext;
148 
149  /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
150  different to the ones in <ucontext.h>. */
151 
152  pc = (u1 *) _mc->psw.addr;
153 
154  t->pc = pc;
155 }
156 #endif
157 
158 
159 /**
160  * Read the given context into an executionstate.
161  *
162  * @param es execution state
163  * @param context machine context
164  */
165 void md_executionstate_read(executionstate_t* es, void* context)
166 {
167  ucontext_t *_uc;
168  mcontext_t *_mc;
169  int i;
170 
171  _uc = (ucontext_t *) context;
172  _mc = &_uc->uc_mcontext;
173 
174  /* read special registers */
175  es->pc = (u1 *) _mc->psw.addr;
176  es->sp = (u1 *) _mc->gregs[REG_SP];
177  es->pv = (u1 *) _mc->gregs[REG_PV] - N_PV_OFFSET;
178  es->ra = (u1 *) _mc->gregs[REG_RA];
179 
180  /* read integer registers */
181  for (i = 0; i < INT_REG_CNT; i++)
182  es->intregs[i] = _mc->gregs[i];
183 
184  /* read float registers */
185  /* Do not use the assignment operator '=', as the type of
186  * the _mc->sc_fpregs[i] can cause invalid conversions. */
187 
188  assert(sizeof(_mc->fpregs.fprs) == sizeof(es->fltregs));
189  os::memcpy(&es->fltregs, &_mc->fpregs.fprs, sizeof(_mc->fpregs.fprs));
190 }
191 
192 
193 /**
194  * Write the given executionstate back to the context.
195  *
196  * @param es execution state
197  * @param context machine context
198  */
200 {
201  ucontext_t *_uc;
202  mcontext_t *_mc;
203  int i;
204 
205  _uc = (ucontext_t *) context;
206  _mc = &_uc->uc_mcontext;
207 
208  /* write integer registers */
209  for (i = 0; i < INT_REG_CNT; i++)
210  _mc->gregs[i] = es->intregs[i];
211 
212  /* write float registers */
213  /* Do not use the assignment operator '=', as the type of
214  * the _mc->sc_fpregs[i] can cause invalid conversions. */
215 
216  assert(sizeof(_mc->fpregs.fprs) == sizeof(es->fltregs));
217  os::memcpy(&_mc->fpregs.fprs, &es->fltregs, sizeof(_mc->fpregs.fprs));
218 
219  /* write special registers */
220  _mc->psw.addr = (ptrint) es->pc;
221  _mc->gregs[REG_SP] = (ptrint) es->sp;
222  _mc->gregs[REG_PV] = (ptrint) es->pv + N_PV_OFFSET;
223  _mc->gregs[REG_RA] = (ptrint) es->ra;
224 }
225 
226 
227 /* md_jit_method_patch_address *************************************************
228 
229  Gets the patch address of the currently compiled method. The offset
230  is extracted from the load instruction(s) before the jump and added
231  to the right base address (PV or REG_METHODPTR).
232 
233  INVOKESTATIC/SPECIAL:
234 
235 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
236 (load dseg offset)
237 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
238 (load pv)
239 0x7748d7ba: 0d ed basr %r14,%r13
240 (jump to pv)
241 
242  INVOKEVIRTUAL:
243 
244 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
245 (load mptr)
246 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
247 (load pv from mptr)
248 0x7748d832: 0d ed basr %r14,%r13
249 (jump to pv)
250 
251 
252  INVOKEINTERFACE:
253 
254 last 2 instructions the same as in invokevirtual
255 
256 *******************************************************************************/
257 
258 void *md_jit_method_patch_address(void* pv, void *ra, void *mptr)
259 {
260  uint8_t *pc;
261  uint8_t base, index;
262  int32_t offset;
263  void *pa; /* patch address */
264 
265  /* go back to the load before the call instruction */
266 
267  pc = ((uint8_t *) ra) - SZ_BCR - SZ_L;
268 
269  /* get the base register of the load */
270 
271  base = N_RX_GET_BASE(pc);
272  index = N_RX_GET_INDEX(pc);
273 
274  /* check for the different calls */
275 
276  switch (base) {
277  case REG_PV:
278  /* INVOKESTATIC/SPECIAL */
279 
280  switch (index) {
281  case R0:
282  /* the offset is in the load instruction */
283  offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
284  break;
285  case REG_ITMP1:
286  /* the offset is in the immediate load before the load */
287  offset = N_RI_GET_IMM(pc - SZ_L);
288  break;
289  default:
290  assert(0);
291  }
292 
293  /* add the offset to the procedure vector */
294 
295  pa = ((uint8_t *) pv) + offset;
296  break;
297 
298  case REG_METHODPTR:
299  /* mptr relative */
300  /* INVOKEVIRTUAL/INTERFACE */
301 
302  offset = N_RX_GET_DISP(pc);
303 
304  /* return NULL if no mptr was specified (used for replacement) */
305 
306  if (mptr == NULL)
307  return NULL;
308 
309  /* add offset to method pointer */
310 
311  pa = (uint8_t *)mptr + offset;
312  break;
313 
314  default:
315  /* catch any problems */
316  vm_abort("md_jit_method_patch_address");
317  break;
318  }
319 
320  return pa;
321 }
322 
323 
324 /**
325  * Decode the trap instruction at the given PC.
326  *
327  * @param trp information about trap to be filled
328  * @param sig signal number
329  * @param xpc exception PC
330  * @param es execution state of the machine
331  * @return true if trap was decoded successfully, false otherwise.
332  */
333 bool md_trap_decode(trapinfo_t* trp, int sig, void* xpc, executionstate_t* es)
334 {
335  switch (sig) {
336  case TRAP_SIGILL:
337  if (N_RR_GET_OPC((uint8_t*) xpc) == OPC_ILL) {
338  int32_t reg = N_ILL_GET_REG((uint8_t*) xpc);
339  trp->type = N_ILL_GET_TYPE((uint8_t*) xpc);
340  trp->value = es->intregs[reg];
341  return true;
342  }
343  return false;
344 
345  case TRAP_SIGSEGV:
346  {
347  int is_null;
348  int32_t base;
349  switch (N_RX_GET_OPC((uint8_t*) xpc)) {
350  case OPC_L:
351  case OPC_ST:
352  case OPC_CL: /* array size check on NULL array */
353  base = N_RX_GET_BASE((uint8_t*) xpc);
354  if (base == 0) {
355  is_null = 1;
356  } else if (es->intregs[base] == 0) {
357  is_null = 1;
358  } else {
359  is_null = 0;
360  }
361  break;
362  default:
363  is_null = 0;
364  break;
365  }
366 
367  // Check for implicit NullPointerException.
368  if (is_null) {
370  trp->value = 0;
371  return true;
372  }
373 
374  return false;
375  }
376 
377  case TRAP_SIGFPE:
378  {
379  if (N_RR_GET_OPC((uint8_t*) xpc) == OPC_DR) {
380  int r2 = N_RR_GET_REG2((uint8_t*) xpc);
381  if (es->intregs[r2] == 0) {
383  trp->value = 0;
384  return true;
385  }
386  }
387 
388  return false;
389  }
390 
391  default:
392  return false;
393  }
394 }
395 
396 
397 
398 /* md_patch_replacement_point **************************************************
399 
400  Patch the given replacement point.
401 
402 *******************************************************************************/
403 #if defined(ENABLE_REPLACEMENT)
404 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
405 {
406  assert(0);
407 }
408 #endif
409 
410 extern "C" {
411 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
412 
413  uint8_t *xptr;
414  uint8_t *xpc;
415  uint8_t *sp;
416  uint8_t *pv;
417  uint8_t *ra;
418  uint8_t *handler;
419  int32_t framesize;
420  int32_t intsave;
421  int32_t fltsave;
422  int64_t *savearea;
423  int i;
424  int reg;
425  int loops = 0;
426 
427  /* get registers */
428 
429  xptr = *(uint8_t **)(regs + REG_ITMP1_XPTR);
430  xpc = *(uint8_t **)(regs + REG_ITMP2_XPC);
431  sp = *(uint8_t **)(regs + REG_SP);
432 
433 
434  /* initialize number of calle saved int regs to restore to 0 */
435  out[0] = 0;
436 
437  /* initialize number of calle saved flt regs to restore to 0 */
438  out[1] = 0;
439 
440  do {
441 
442  ++loops;
443 
444  pv = (uint8_t*) methodtree_find(xpc);
445 
446  handler = (uint8_t*) exceptions_handle_exception((java_object_t *)xptr, xpc, pv, sp);
447 
448  if (handler == NULL) {
449 
450  /* exception was not handled
451  * get values of calee saved registers and remove stack frame
452  */
453 
454  /* read stuff from data segment */
455 
456  framesize = *(int32_t *)(pv + FrameSize);
457 
458  intsave = *(int32_t *)(pv + IntSave);
459  if (intsave > out[0]) {
460  out[0] = intsave;
461  }
462 
463  fltsave = *(int32_t *)(pv + FltSave);
464  if (fltsave > out[1]) {
465  out[1] = fltsave;
466  }
467 
468  /* pointer to register save area */
469 
470  savearea = (int64_t *)(sp + framesize - 8);
471 
472  /* return address */
473 
474  ra = *(uint8_t **)(sp + framesize - 8);
475 
476  /* restore saved registers */
477 
478  for (i = 0; i < intsave; ++i) {
479  --savearea;
481  regs[reg] = *(int32_t *)(savearea);
482  }
483 
484  for (i = 0; i < fltsave; ++i) {
485  --savearea;
487  fregs[reg] = *savearea;
488  }
489 
490  /* remove stack frame */
491 
492  sp += framesize;
493 
494  /* new xpc is call before return address */
495 
496  xpc = ra - 2;
497 
498  } else {
499  xpc = handler;
500  }
501  } while (handler == NULL);
502 
503  /* write new values for registers */
504 
505  *(uint8_t **)(regs + REG_ITMP1_XPTR) = xptr;
506  *(uint8_t **)(regs + REG_ITMP2_XPC) = xpc;
507  *(uint8_t **)(regs + REG_SP) = sp;
508  *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
509 
510  /* maybe leaf flag */
511 
512  out[2] = (loops == 1);
513 }
514 }
515 
516 /*
517  * These are local overrides for various environment variables in Emacs.
518  * Please do not remove this and leave it at the end of the file, where
519  * Emacs will automagically detect them.
520  * ---------------------------------------------------------------------
521  * Local variables:
522  * mode: c++
523  * indent-tabs-mode: t
524  * c-basic-offset: 4
525  * tab-width: 4
526  * End:
527  * vim:noexpandtab:sw=4:ts=4:
528  */
#define REG_SP
Definition: md-abi.hpp:53
#define methodtree_find
Definition: md-asm.hpp:101
#define OPC_ILL
Definition: codegen.hpp:387
std::size_t index
#define pv
Definition: md-asm.hpp:65
#define REG_PV
Definition: md-abi.hpp:42
intptr_t value
Value (numeric or address) passed with the trap.
Definition: trap.hpp:44
#define mptr
Definition: md-asm.hpp:66
#define OPC_ST
Definition: codegen.hpp:531
#define OPC_L
Definition: codegen.hpp:483
char * regs[]
Definition: disass.c:51
#define ra
Definition: md-asm.hpp:62
static uint8_t N_RX_GET_OPC(uint8_t *instrp)
Definition: codegen.hpp:234
#define FltSave
#define N_PV_OFFSET
Definition: codegen.hpp:339
void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
NullPointerException signal handler for hardware null pointer check.
Definition: md-os.cpp:50
#define OPC_CL
Definition: codegen.hpp:455
Contains information about a decoded trap instruction.
Definition: trap.hpp:42
static uint8_t N_ILL_GET_TYPE(uint8_t *instrp)
Definition: codegen.hpp:394
void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
Illegal Instruction signal handler for hardware exception checks.
Definition: md-os.cpp:65
static int16_t N_RI_GET_IMM(uint8_t *instrp)
Definition: codegen.hpp:261
struct sigcontext uc_mcontext
Definition: md-os.cpp:42
#define REG_ITMP1_XPTR
Definition: md-abi.hpp:50
#define INT_REG_CNT
Definition: md-abi.hpp:72
#define r2
Definition: md-asm.hpp:39
uint8_t u1
Definition: types.hpp:40
const s4 abi_registers_integer_saved[]
Definition: md-abi.cpp:75
static uint16_t N_RX_GET_DISP(uint8_t *instrp)
Definition: codegen.hpp:250
#define exceptions_handle_exception
Definition: md-asm.hpp:102
#define REG_ITMP2_XPC
Definition: md-abi.hpp:51
void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
Definition: md-os.cpp:59
void vm_abort(const char *text,...)
Definition: vm.cpp:2586
#define INT_SAV_CNT
Definition: md-abi.hpp:73
#define xpc
Definition: md-asm.hpp:51
void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
Definition: md-os.cpp:83
#define R0
Definition: md-abi.hpp:31
const s4 abi_registers_float_saved[]
Definition: md-abi.cpp:118
#define OPC_DR
Definition: codegen.hpp:469
static uint8_t N_RX_GET_BASE(uint8_t *instrp)
Definition: codegen.hpp:246
int type
Specific trap type (see md-trap.h).
Definition: trap.hpp:43
#define r1
Definition: md-asm.hpp:38
MIIterator i
static void * memcpy(void *dest, const void *src, size_t n)
Definition: os.hpp:492
void md_executionstate_write(executionstate_t *es, void *context)
Definition: md-os.cpp:147
#define REG_RA
Definition: md-abi.hpp:41
static uint8_t N_RR_GET_REG1(uint8_t *instrp)
Definition: codegen.hpp:218
void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out)
Definition: md.cpp:411
#define SZ_L
Definition: codegen.hpp:482
void * md_jit_method_patch_address(void *pv, void *ra, void *mptr)
Definition: md.cpp:83
CONTEXT mcontext_t
Definition: ucontext.h:27
#define FLT_SAV_CNT
Definition: md-abi.hpp:80
#define sp
Definition: md-asm.hpp:81
#define pc
Definition: md-asm.hpp:56
#define SZ_BCR
Definition: codegen.hpp:423
void md_executionstate_read(executionstate_t *es, void *context)
Definition: md-os.cpp:107
#define IntSave
bool md_trap_decode(trapinfo_t *trp, int sig, void *xpc, executionstate_t *es)
Decode the trap instruction at the given PC.
Definition: md.cpp:192
#define REG_METHODPTR
Definition: md-abi.hpp:43
void trap_handle(int sig, void *xpc, void *context)
Handles the signal which is generated by trap instructions, caught by a signal handler and calls the ...
Definition: trap.cpp:101
static uint8_t N_RR_GET_OPC(uint8_t *instrp)
Definition: codegen.hpp:214
OStream & out()
Definition: OStream.cpp:39
uintptr_t intregs[INT_REG_CNT]
static uint8_t N_ILL_GET_REG(uint8_t *instrp)
Definition: codegen.hpp:390
static uint8_t N_RR_GET_REG2(uint8_t *instrp)
Definition: codegen.hpp:222
void md_init(void)
Definition: md.cpp:48
uintptr_t ptrint
Definition: types.hpp:54
static uint8_t N_RX_GET_INDEX(uint8_t *instrp)
Definition: codegen.hpp:242
#define FrameSize
double fltregs[FLT_REG_CNT]
#define THREADOBJECT
Definition: thread-none.hpp:47
#define REG_ITMP1
Definition: md-abi.hpp:46
#define xptr
Definition: md-asm.hpp:50