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