CACAO
executionstate.cpp
Go to the documentation of this file.
1 /* src/vm/jit/executionstate.cpp - execution-state handling
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 
26 #include <stdint.h> // for uintptr_t, int32_t, uint8_t, etc
27 #include <string.h> // for memcmp
28 #include <cstdio> // for printf
29 #include "config.h" // for SIZEOF_VOID_P
30 #include "arch.hpp"
31 #include "md-abi.hpp" // for FLT_REG_CNT, INT_REG_CNT
32 #include "md.hpp" // for md_codegen_get_pv_from_pc, etc
33 #include "vm/descriptor.hpp" // for methoddesc
34 #include "vm/exceptions.hpp" // for exceptions_handle_exception
35 #include "vm/jit/abi.hpp" // for nregdescfloat, nregdescint
36 #include "vm/jit/code.hpp" // for codeinfo, etc
37 #include "vm/method.hpp" // for method_print, methodinfo
38 #include "vm/os.hpp" // for os
39 #include "vm/types.hpp" // for s4, ptrint, u1, u8
40 
41 /**
42  * Restore callee-saved registers (including the RA register),
43  * set the stack pointer to the next stackframe,
44  * set the PC to the return address of the popped frame.
45  *
46  * *** This function imitates the effects of the method epilog ***
47  * *** and returning from the method call. ***
48  *
49  * @param es Execution state to be modified.
50  * NOTE: es->code and es->pv are NOT updated.
51  */
53 {
54  int32_t reg;
55  int32_t i;
56 
57  // Sanity checks.
58  assert(es->code != NULL);
59 
60  // Calculate the size of the stackframe.
61  int32_t framesize = md_stacktrace_get_framesize(es->code);
62 
63  // Read the return address.
64  uint8_t* ra;
65 #if STACKFRAME_LEAFMETHODS_RA_REGISTER
66  if (code_is_leafmethod(es->code))
67  ra = es->ra;
68  else
69 #endif
70  ra = (u1*) md_stacktrace_get_returnaddress(es->sp, framesize);
71 
72  // Calculate the base of the stack frame.
73  uintptr_t sp = (uintptr_t) es->sp;
74  uintptr_t basesp = sp + framesize;
75 
76  // Restore return address, if part of frame.
79  if (!code_is_leafmethod(es->code)) {
80 # endif
81 # if STACKFRAME_PACKED_SAVED_REGISTERS
82  basesp -= 1 * SIZEOF_VOID_P;
83 # else
84  basesp -= 1 * SIZE_OF_STACKSLOT;
85 # endif
86  es->ra = *((uint8_t**) basesp);
87 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
88  }
89 # endif
90 #endif /* STACKFRAME_RA_TOP_OF_FRAME */
91 
92  // Restore return address, if inside linkage area.
93 #if STACKFRAME_RA_LINKAGE_AREA
94 # if STACKFRAME_LEAFMETHODS_RA_REGISTER
95  if (!code_is_leafmethod(es->code))
96 # endif
97  es->ra = *((uint8_t**) (basesp + LA_LR_OFFSET));
98 #endif /* STACKFRAME_RA_LINKAGE_AREA */
99 
100 #if defined(__AARCH64__) || defined(__X86_64__)
101  // Recover the frame-pointer
102  if (code_is_using_frameptr(es->code)) {
103  basesp -= 1 * SIZE_OF_STACKSLOT;
104 # if defined(__X86_64__)
105  es->intregs[RBP] = *((uintptr_t*) basesp);
106 # elif defined(__AARCH64__)
107  es->intregs[REG_FP] = *((uintptr_t*) basesp);
108 # endif
109  }
110 #endif
111 
112 #if defined(__AARCH64__)
113  // If the stack was padded for 16-byte alignment, do it here
114  if (framesize != es->code->stackframesize * SIZE_OF_STACKSLOT) {
115  basesp -= 1 * SIZE_OF_STACKSLOT;
116  }
117 #endif
118 
119  // Restore saved int registers.
120  reg = INT_REG_CNT;
121  for (i=0; i<es->code->savedintcount; ++i) {
122  while (nregdescint[--reg] != REG_SAV)
123  ;
124 #if STACKFRAME_PACKED_SAVED_REGISTERS
125  basesp -= 1 * SIZEOF_VOID_P;
126 #else
127  basesp -= 1 * SIZE_OF_STACKSLOT;
128 #endif
129  es->intregs[reg] = *((uintptr_t*) basesp);
130  }
131 
132  // Restore saved flt registers.
133  // XXX align?
134  reg = FLT_REG_CNT;
135  for (i=0; i<es->code->savedfltcount; ++i) {
136  while (nregdescfloat[--reg] != REG_SAV)
137  ;
139  es->fltregs[reg] = *((double*) basesp);
140  }
141 
142  // Adjust the stackpointer.
143  es->sp += framesize;
144 #if STACKFRAME_RA_BETWEEN_FRAMES
145  es->sp += SIZEOF_VOID_P; /* skip return address */
146 #endif
147 
148  // Set the program counter to the return address.
149  es->pc = ra;
150 
151  // In debugging mode clobber non-saved registers.
152 #if !defined(NDEBUG)
153  for (i=0; i<INT_REG_CNT; ++i)
154  if (nregdescint[i] != REG_SAV && nregdescint[i] != REG_RES)
155  es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
156  for (i=0; i<FLT_REG_CNT; ++i)
157  if (nregdescfloat[i] != REG_SAV && nregdescfloat[i] != REG_RES)
158  *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
159 #endif /* !defined(NDEBUG) */
160 }
161 
162 /**
163  * Performs stack unwinding in case of an exception. This is done by
164  * popping frames off the given execution state until a frame is reached
165  * for which there is a handler. Execution will continue at the handler
166  * site once the execution state is written back to the machine.
167  *
168  * @param es Execution state to be modified.
169  * @param e The thrown exception object.
170  *
171  * This is specified in:
172  * The Java(TM) Virtual Machine Specification, Second Edition
173  * Section 3.6.5: Abrupt Method Invocation Completion
174  */
176 {
177  void* handler = NULL;
178 
179  // Iterate until we find an exception handler.
180  while (handler == NULL) {
181 
182  // Search an exception handler in the current frame.
183  handler = exceptions_handle_exception(e, es->pc, es->pv, es->sp);
184 
185  // Jump directly into the handler in case we found one.
186  if (handler != NULL)
187  break;
188 
189  // Find the codeinfo structure for the current frame.
190  es->code = code_get_codeinfo_for_pv(es->pv);
191 
192  // Pop one frame off the stack.
194 
195  // Get the PV for the parent Java method.
196  es->pv = (uint8_t*) md_codegen_get_pv_from_pc(es->pc);
197 
198  // After popping the frame the PC points to the instruction just after
199  // the invocation. To get the XPC we need to correct the PC to point
200  // just before the invocation. But we do not know how big the
201  // invocation site actually is, so we subtract one, which should be
202  // sufficient for our purposes.
203  es->pc -= 1;
204  }
205 
206  // Update the execution state to continue at the handler site.
207  es->pc = (uint8_t*) handler;
208 }
209 
210 
211 /* executionstate_sanity_check *************************************************
212 
213  Perform some sanity checks for the md_executionstate_read and
214  md_executionstate_write functions.
215 
216 *******************************************************************************/
217 
218 #if !defined(NDEBUG)
219 void executionstate_sanity_check(void *context)
220 {
221  /* estimate a minimum for the context size */
222 
223 #define MINIMUM_CONTEXT_SIZE (SIZEOF_VOID_P * INT_REG_CNT \
224  + sizeof(double) * FLT_REG_CNT)
225 
226  executionstate_t es1;
227  executionstate_t es2;
228  executionstate_t es3;
229  unsigned int i;
230  unsigned char reference[MINIMUM_CONTEXT_SIZE];
231 
232  /* keep a copy of (a prefix of) the context for reference */
233 
234  os::memcpy(&reference, context, MINIMUM_CONTEXT_SIZE);
235 
236  /* different poisons */
237 
238  os::memset(&es1, 0xc9, sizeof(executionstate_t));
239  os::memset(&es2, 0xb5, sizeof(executionstate_t));
240  os::memset(&es3, 0x6f, sizeof(executionstate_t));
241 
242  md_executionstate_read(&es1, context);
243 
244  /* verify that item-by-item copying preserves the state */
245 
246  es2.pc = es1.pc;
247  es2.sp = es1.sp;
248  es2.pv = es1.pv;
249  es2.ra = es1.ra;
250  es2.code = es1.code;
251  for (i = 0; i < INT_REG_CNT; ++i)
252  es2.intregs[i] = es1.intregs[i];
253  for (i = 0; i < FLT_REG_CNT; ++i)
254  es2.fltregs[i] = es1.fltregs[i];
255 
256  /* write it back - this should not change the context */
257  /* We cannot check that completely, unfortunately, as we don't know */
258  /* the size of the (OS-dependent) context. */
259 
260  md_executionstate_write(&es2, context);
261 
262  /* Read it again, Sam! */
263 
264  md_executionstate_read(&es3, context);
265 
266  /* Compare. Note: Because of the NAN madness, we cannot compare
267  * doubles using '=='. */
268 
269  assert(es3.pc == es1.pc);
270  assert(es3.sp == es1.sp);
271  assert(es3.pv == es1.pv);
272  for (i = 0; i < INT_REG_CNT; ++i)
273  assert(es3.intregs[i] == es1.intregs[i]);
274  for (i = 0; i < FLT_REG_CNT; ++i)
275  assert(memcmp(es3.fltregs+i, es1.fltregs+i, sizeof(double)) == 0);
276 
277  /* i386 and x86_64 do not have an RA register */
278 
279 #if defined(__I386__) || defined(__X86_64__)
280  assert(es3.ra != es1.ra);
281 #else
282  assert(es3.ra == es1.ra);
283 #endif
284 
285  /* "code" is not set by the md_* functions */
286 
287  assert(es3.code != es1.code);
288 
289  /* assert that we have not messed up the context */
290 
291  assert(memcmp(&reference, context, MINIMUM_CONTEXT_SIZE) == 0);
292 }
293 #endif
294 
295 
296 /* executionstate_println ******************************************************
297 
298  Print execution state
299 
300  IN:
301  es...............the execution state to print
302 
303 *******************************************************************************/
304 
305 #if !defined(NDEBUG)
307 {
308  uint64_t *sp;
309  int slots;
310  int extraslots;
311  int i;
312 
313  if (!es) {
314  printf("(executionstate_t *)NULL\n");
315  return;
316  }
317 
318  printf("executionstate_t:\n");
319  printf("\tpc = %p", es->pc);
320  printf(" sp = %p", es->sp);
321  printf(" pv = %p", es->pv);
322  printf(" ra = %p\n", es->ra);
323 
324 #if defined(ENABLE_DISASSEMBLER)
325  for (i=0; i<INT_REG_CNT; ++i) {
326  if (i%4 == 0)
327  printf("\t");
328  else
329  printf(" ");
330 # if SIZEOF_VOID_P == 8
331  printf("%-3s = %016lx", abi_registers_integer_name[i], es->intregs[i]);
332 # else
333  printf("%-3s = %08x", abi_registers_integer_name[i], (unsigned) es->intregs[i]);
334 # endif
335  if (i%4 == 3)
336  printf("\n");
337  }
338 
339  for (i=0; i<FLT_REG_CNT; ++i) {
340  if (i%4 == 0)
341  printf("\t");
342  else
343  printf(" ");
344  printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
345  if (i%4 == 3)
346  printf("\n");
347  }
348 #endif
349 
350  sp = (uint64_t *) es->sp;
351 
352  extraslots = 2;
353 
354  if (es->code) {
355  methoddesc *md = es->code->m->parseddesc;
356  slots = es->code->stackframesize;
357  extraslots = 1 + md->memuse;
358  }
359  else
360  slots = 0;
361 
362 
363  if (slots) {
364  printf("\tstack slots(+%d) at sp:", extraslots);
365  for (i=0; i<slots+extraslots; ++i) {
366  if (i%4 == 0)
367  printf("\n\t\t");
368  printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
369  printf("%016llx",(unsigned long long)*sp++);
370  printf("%c", (i >= slots) ? ')' : ' ');
371  }
372  printf("\n");
373  }
374 
375  printf("\tcode: %p", (void*)es->code);
376  if (es->code != NULL) {
377  printf(" stackframesize=%d ", es->code->stackframesize);
378  method_print(es->code->m);
379  }
380  printf("\n");
381 
382  printf("\n");
383 }
384 #endif
385 
386 
387 /*
388  * These are local overrides for various environment variables in Emacs.
389  * Please do not remove this and leave it at the end of the file, where
390  * Emacs will automagically detect them.
391  * ---------------------------------------------------------------------
392  * Local variables:
393  * mode: c++
394  * indent-tabs-mode: t
395  * c-basic-offset: 4
396  * tab-width: 4
397  * End:
398  * vim:noexpandtab:sw=4:ts=4:
399  */
static void * memset(void *s, int c, size_t n)
Definition: os.hpp:501
#define ra
Definition: md-asm.hpp:62
void method_print(methodinfo *m)
Definition: method.cpp:1189
void executionstate_pop_stackframe(executionstate_t *es)
Restore callee-saved registers (including the RA register), set the stack pointer to the next stackfr...
#define REG_SAV
Definition: jit.hpp:449
uint8_t savedfltcount
Definition: code.hpp:90
int32_t stackframesize
Definition: code.hpp:87
s4 nregdescint[]
Definition: md-abi.cpp:41
#define STACKFRAME_RA_TOP_OF_FRAME
Definition: arch.hpp:111
#define LA_LR_OFFSET
Definition: md-abi.hpp:97
#define MINIMUM_CONTEXT_SIZE
#define INT_REG_CNT
Definition: md-abi.hpp:74
#define STACKFRAME_LEAFMETHODS_RA_REGISTER
Definition: arch.hpp:113
#define REG_RES
Definition: jit.hpp:446
uint8_t u1
Definition: types.hpp:40
static int code_is_using_frameptr(codeinfo *code)
Definition: code.hpp:194
static int code_is_leafmethod(codeinfo *code)
Definition: code.hpp:150
#define exceptions_handle_exception
Definition: md-asm.hpp:102
methodinfo * m
Definition: code.hpp:74
void executionstate_println(executionstate_t *es)
uint64_t u8
Definition: types.hpp:49
static codeinfo * code_get_codeinfo_for_pv(void *pv)
Definition: code.hpp:222
MIIterator i
void executionstate_unwind_exception(executionstate_t *es, java_handle_t *e)
Performs stack unwinding in case of an exception.
#define SIZE_OF_STACKSLOT
Definition: simplereg.cpp:80
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:148
static void * md_codegen_get_pv_from_pc(void *ra)
Definition: md.hpp:100
#define STACK_SLOTS_PER_FLOAT
const char * abi_registers_integer_name[]
Definition: md-abi.cpp:57
MIIterator e
methoddesc * parseddesc
Definition: method.hpp:78
#define sp
Definition: md-asm.hpp:81
void md_executionstate_read(executionstate_t *es, void *context)
Definition: md-os.cpp:107
static void * md_stacktrace_get_returnaddress(void *sp, int32_t stackframesize)
Definition: md.hpp:77
void executionstate_sanity_check(void *context)
uintptr_t intregs[INT_REG_CNT]
#define REG_FP
Definition: md-abi.hpp:53
s4 nregdescfloat[]
Definition: md-abi.cpp:98
uintptr_t ptrint
Definition: types.hpp:54
double fltregs[FLT_REG_CNT]
#define printf(...)
Definition: ssa2.cpp:40
uint8_t savedintcount
Definition: code.hpp:89
#define FLT_REG_CNT
Definition: md-abi.hpp:81
static int32_t md_stacktrace_get_framesize(codeinfo *code)
Returns the size (in bytes) of the current stackframe, specified by the passed codeinfo structure...
Definition: md.hpp:57
#define RBP
Definition: md-abi.hpp:37