* src/vm/jit/executionstate.c (executionstate_pop_stackframe): Moved here from
[cacao.git] / src / vm / jit / executionstate.c
1 /* src/vm/jit/executionstate.c - execution-state handling
2
3    Copyright (C) 2007, 2008
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 /* executionstate_sanity_check *************************************************
154
155    Perform some sanity checks for the md_executionstate_read and
156    md_executionstate_write functions.
157
158 *******************************************************************************/
159
160 #if !defined(NDEBUG)
161 void executionstate_sanity_check(void *context)
162 {
163     /* estimate a minimum for the context size */
164
165 #if defined(HAS_ADDRESS_REGISTER_FILE)
166 #define MINIMUM_CONTEXT_SIZE  (SIZEOF_VOID_P    * ADR_REG_CNT \
167                                        + sizeof(double) * FLT_REG_CNT \
168                                                            + sizeof(int)    * INT_REG_CNT)
169 #else
170 #define MINIMUM_CONTEXT_SIZE  (SIZEOF_VOID_P    * INT_REG_CNT \
171                                        + sizeof(double) * FLT_REG_CNT)
172 #endif
173
174         executionstate_t es1;
175         executionstate_t es2;
176         executionstate_t es3;
177         unsigned int i;
178         unsigned char reference[MINIMUM_CONTEXT_SIZE];
179
180         /* keep a copy of (a prefix of) the context for reference */
181
182         os_memcpy(&reference, context, MINIMUM_CONTEXT_SIZE);
183
184         /* different poisons */
185
186         os_memset(&es1, 0xc9, sizeof(executionstate_t));
187         os_memset(&es2, 0xb5, sizeof(executionstate_t));
188         os_memset(&es3, 0x6f, sizeof(executionstate_t));
189
190         md_executionstate_read(&es1, context);
191
192         /* verify that item-by-item copying preserves the state */
193
194         es2.pc = es1.pc;
195         es2.sp = es1.sp;
196         es2.pv = es1.pv;
197         es2.ra = es1.ra;
198         es2.code = es1.code;
199         for (i = 0; i < INT_REG_CNT; ++i)
200                 es2.intregs[i] = es1.intregs[i];
201         for (i = 0; i < FLT_REG_CNT; ++i)
202                 es2.fltregs[i] = es1.fltregs[i];
203 #if defined(HAS_ADDRESS_REGISTER_FILE)
204         for (i = 0; i < ADR_REG_CNT; ++i)
205                 es2.adrregs[i] = es1.adrregs[i];
206 #endif
207
208         /* write it back - this should not change the context */
209         /* We cannot check that completely, unfortunately, as we don't know */
210         /* the size of the (OS-dependent) context. */
211
212         md_executionstate_write(&es2, context);
213
214         /* Read it again, Sam! */
215
216         md_executionstate_read(&es3, context);
217
218         /* Compare. Note: Because of the NAN madness, we cannot compare
219          * doubles using '=='. */
220
221         assert(es3.pc == es1.pc);
222         assert(es3.sp == es1.sp);
223         assert(es3.pv == es1.pv);
224         for (i = 0; i < INT_REG_CNT; ++i)
225                 assert(es3.intregs[i] == es1.intregs[i]);
226         for (i = 0; i < FLT_REG_CNT; ++i)
227                 assert(memcmp(es3.fltregs+i, es1.fltregs+i, sizeof(double)) == 0);
228 #if defined(HAS_ADDRESS_REGISTER_FILE)
229         for (i = 0; i < ADR_REG_CNT; ++i)
230                 assert(es3.adrregs[i] == es1.adrregs[i]);
231 #endif
232
233         /* i386 and x86_64 do not have an RA register */
234
235 #if defined(__I386__) || defined(__X86_64__)
236         assert(es3.ra != es1.ra);
237 #else
238         assert(es3.ra == es1.ra);
239 #endif
240
241         /* "code" is not set by the md_* functions */
242
243         assert(es3.code != es1.code);
244
245         /* assert that we have not messed up the context */
246
247         assert(memcmp(&reference, context, MINIMUM_CONTEXT_SIZE) == 0);
248 }
249 #endif
250
251
252 /* executionstate_println ******************************************************
253  
254    Print execution state
255   
256    IN:
257        es...............the execution state to print
258   
259 *******************************************************************************/
260
261 #if !defined(NDEBUG)
262 void executionstate_println(executionstate_t *es)
263 {
264         uint64_t *sp;
265         int       slots;
266         int       extraslots;
267         int       i;
268
269         if (!es) {
270                 printf("(executionstate_t *)NULL\n");
271                 return;
272         }
273
274         printf("executionstate_t:\n");
275         printf("\tpc = %p", es->pc);
276         printf("  sp = %p", es->sp);
277         printf("  pv = %p", es->pv);
278         printf("  ra = %p\n", es->ra);
279
280 #if defined(ENABLE_DISASSEMBLER)
281         for (i=0; i<INT_REG_CNT; ++i) {
282                 if (i%4 == 0)
283                         printf("\t");
284                 else
285                         printf(" ");
286 # if SIZEOF_VOID_P == 8
287                 printf("%-3s = %016lx", abi_registers_integer_name[i], es->intregs[i]);
288 # else
289                 printf("%-3s = %08x", abi_registers_integer_name[i], (unsigned) es->intregs[i]);
290 # endif
291                 if (i%4 == 3)
292                         printf("\n");
293         }
294
295         for (i=0; i<FLT_REG_CNT; ++i) {
296                 if (i%4 == 0)
297                         printf("\t");
298                 else
299                         printf(" ");
300                 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
301                 if (i%4 == 3)
302                         printf("\n");
303         }
304
305 # if defined(HAS_ADDRESS_REGISTER_FILE)
306         for (i=0; i<ADR_REG_CNT; ++i) {
307                 if (i%4 == 0)
308                         printf("\t");
309                 else
310                         printf(" ");
311                 printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
312                 if (i%4 == 3)
313                         printf("\n");
314         }
315 # endif
316 #endif
317
318         sp = (uint64_t *) es->sp;
319
320         extraslots = 2;
321
322         if (es->code) {
323                 methoddesc *md = es->code->m->parseddesc;
324                 slots = es->code->stackframesize;
325                 extraslots = 1 + md->memuse;
326         }
327         else
328                 slots = 0;
329
330
331         if (slots) {
332                 printf("\tstack slots(+%d) at sp:", extraslots);
333                 for (i=0; i<slots+extraslots; ++i) {
334                         if (i%4 == 0)
335                                 printf("\n\t\t");
336                         printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
337                         printf("%016llx",(unsigned long long)*sp++);
338                         printf("%c", (i >= slots) ? ')' : ' ');
339                 }
340                 printf("\n");
341         }
342
343         printf("\tcode: %p", (void*)es->code);
344         if (es->code != NULL) {
345                 printf(" stackframesize=%d ", es->code->stackframesize);
346                 method_print(es->code->m);
347         }
348         printf("\n");
349
350         printf("\n");
351 }
352 #endif
353
354
355 /*
356  * These are local overrides for various environment variables in Emacs.
357  * Please do not remove this and leave it at the end of the file, where
358  * Emacs will automagically detect them.
359  * ---------------------------------------------------------------------
360  * Local variables:
361  * mode: c
362  * indent-tabs-mode: t
363  * c-basic-offset: 4
364  * tab-width: 4
365  * End:
366  * vim:noexpandtab:sw=4:ts=4:
367  */