4f3db73e4a14f9b79ffef4323a2547aa5951e04c
[cacao.git] / src / vm / jit / stack.h
1 /* vm/jit/stack.h - stack analysis header
2
3    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Christian Thalinger
28
29    Changes: Christian Ullrich
30
31    $Id: stack.h 4683 2006-03-23 00:30:30Z edwin $
32
33 */
34
35
36 #ifndef _STACK_H
37 #define _STACK_H
38
39 #include "config.h"
40
41 #include "vm/types.h"
42
43 #include "vm/exceptions.h"
44 #include "vm/global.h"
45 #include "vm/jit/jit.h"
46 #include "vm/jit/reg.h"
47
48
49 /* macros used internally by analyse_stack ************************************/
50
51 #if defined(ENABLE_LSRA)
52 # define INC_LIFETIMES(a) { m->maxlifetimes += (a); }
53 #else
54 # define INC_LIFETIMES(a)
55 #endif
56
57 /* convenient abbreviations */
58 #define CURKIND    curstack->varkind
59 #define CURTYPE    curstack->type
60
61
62 /*--------------------------------------------------*/
63 /* STACK DEPTH CHECKING                             */
64 /*--------------------------------------------------*/
65
66 #if defined(ENABLE_VERIFIER)
67 #define CHECK_STACK_DEPTH(depthA,depthB) \
68         do { \
69                 if ((depthA) != (depthB)) \
70                         goto throw_stack_depth_error; \
71         } while (0)
72 #else /* !ENABLE_VERIFIER */
73 #define CHECK_STACK_DEPTH(depthA,depthB)
74 #endif /* ENABLE_VERIFIER */
75
76 /*--------------------------------------------------*/
77 /* BASIC TYPE CHECKING                              */
78 /*--------------------------------------------------*/
79
80 /* XXX would be nice if we did not have to pass the expected type */
81
82 #if defined(ENABLE_VERIFIER)
83 #define CHECK_BASIC_TYPE(expected,actual) \
84         do { \
85                 if ((actual) != (expected)) { \
86                         expectedtype = (expected); \
87                         goto throw_stack_type_error; \
88                 } \
89         } while (0)
90 #else /* !ENABLE_VERIFIER */
91 #define CHECK_BASIC_TYPE(expected,actual)
92 #endif /* ENABLE_VERIFIER */
93
94 /*--------------------------------------------------*/
95 /* STACK UNDERFLOW/OVERFLOW CHECKS                  */
96 /*--------------------------------------------------*/
97
98 /* underflow checks */
99
100 #if defined(ENABLE_VERIFIER)
101 #define REQUIRE(num) \
102     do { \
103         if (stackdepth < (num)) \
104                         goto throw_stack_underflow; \
105         } while (0)
106 #else /* !ENABLE_VERIFIER */
107 #define REQUIRE(num)
108 #endif /* ENABLE_VERIFIER */
109
110 #define REQUIRE_1     REQUIRE(1)
111 #define REQUIRE_2     REQUIRE(2)
112 #define REQUIRE_3     REQUIRE(3)
113 #define REQUIRE_4     REQUIRE(4)
114
115
116 /* overflow check */
117 /* We allow ACONST instructions inserted as arguments to builtin
118  * functions to exceed the maximum stack depth.  Maybe we should check
119  * against maximum stack depth only at block boundaries?
120  */
121
122 /* XXX we should find a way to remove the opc/op1 check */
123 #if defined(ENABLE_VERIFIER)
124 #define CHECKOVERFLOW \
125         do { \
126                 if (stackdepth > m->maxstack) \
127                         if (iptr[0].opc != ICMD_ACONST || iptr[0].op1 == 0) \
128                                 goto throw_stack_overflow; \
129         } while(0)
130 #else /* !ENABLE_VERIFIER */
131 #define CHECKOVERFLOW
132 #endif /* ENABLE_VERIFIER */
133
134 /*--------------------------------------------------*/
135 /* ALLOCATING STACK SLOTS                           */
136 /*--------------------------------------------------*/
137
138 #define NEWSTACK_(s,v,n) \
139     do { \
140         new->prev = curstack; \
141         new->type = (s); \
142         new->flags = 0; \
143         new->varkind = (v); \
144         new->varnum = (n); \
145         curstack = new; \
146         new++; \
147     } while (0)
148
149
150 /* Initialize regoff, so -sia can show regnames even before reg.inc */
151 /* regs[rd->intregargnum has to be set for this */
152 /* new->regoff = (IS_FLT_DBL_TYPE(s))?-1:rd->intreg_argnum; }*/
153
154 #define NEWSTACK(s,v,n) { NEWSTACK_(s,v,n); INC_LIFETIMES(1); }
155
156 #define NEWSTACKn(s,n)  NEWSTACK(s,UNDEFVAR,n)
157 #define NEWSTACK0(s)    NEWSTACK(s,UNDEFVAR,0)
158
159 /* allocate the input stack for an exception handler */
160 #define NEWXSTACK   {NEWSTACK(TYPE_ADR,STACKVAR,0);curstack=0;}
161
162
163 /*--------------------------------------------------*/
164 /* STACK MANIPULATION                               */
165 /*--------------------------------------------------*/
166
167 /* resetting to an empty operand stack */
168
169 #define STACKRESET \
170     do { \
171         curstack = 0; \
172         stackdepth = 0; \
173     } while (0)
174
175
176 /* set the output stack of the current instruction */
177
178 #define SETDST    iptr->dst = curstack;
179
180
181 /* The following macros do NOT check stackdepth, set stackdepth or iptr->dst */
182
183 #define POP(s) \
184     do { \
185                 CHECK_BASIC_TYPE((s),curstack->type); \
186         if (curstack->varkind == UNDEFVAR) \
187             curstack->varkind = TEMPVAR; \
188         curstack = curstack->prev; \
189     } while (0)
190
191 #define POPANY \
192     do { \
193         if (curstack->varkind == UNDEFVAR) \
194             curstack->varkind = TEMPVAR; \
195         curstack = curstack->prev; \
196     } while (0)
197
198 /* Do not copy Interface Stackslots over DUPx, Swaps! */
199 #define COPY(s,d) \
200     do { \
201         (d)->flags = 0; \
202         (d)->type = (s)->type; \
203                 if ( (s)->varkind != STACKVAR) {                \
204                         (d)->varkind = (s)->varkind; \
205                         (d)->varnum = (s)->varnum;       \
206                 } else { \
207                         (d)->varkind = TEMPVAR; \
208                         (d)->varnum = 0; \
209                 } \
210     } while (0)
211
212
213 /*--------------------------------------------------*/
214 /* STACK OPERATIONS MODELING                        */
215 /*--------------------------------------------------*/
216
217 /* The following macros are used to model the stack manipulations of
218  * different kinds of instructions.
219  *
220  * These macros check the input stackdepth and they set the output
221  * stackdepth and the output stack of the instruction (iptr->dst).
222  *
223  * These macros do *not* check for stack overflows!
224  */
225
226 #define PUSHCONST(s){NEWSTACKn(s,stackdepth);SETDST;stackdepth++;}
227 #define LOAD(s,v,n) {NEWSTACK(s,v,n);SETDST;stackdepth++;}
228 #define STORE(s)    {REQUIRE_1;POP(s);SETDST;stackdepth--;}
229
230 #define OP1_0(s) \
231     do { \
232         REQUIRE_1; \
233         POP(s); \
234         SETDST; \
235         stackdepth--; \
236     } while (0)
237
238 #define OP1_0ANY \
239     do { \
240         REQUIRE_1; \
241         POPANY; \
242         SETDST; \
243         stackdepth--; \
244     } while (0)
245
246 #define OP0_1(s) \
247     do { \
248         NEWSTACKn(s, stackdepth); \
249         SETDST; \
250         stackdepth++; \
251     } while (0)
252
253 #define OP1_1(s,d) \
254     do { \
255         REQUIRE_1; \
256         POP(s); \
257         NEWSTACKn(d, stackdepth - 1);\
258         SETDST; \
259     } while (0)
260
261 #define OP2_0(s) \
262     do { \
263         REQUIRE_2; \
264         POP(s); \
265         POP(s); \
266         SETDST; \
267         stackdepth -= 2; \
268     } while (0)
269
270 #define OPTT2_0(t,b) \
271     do { \
272         REQUIRE_2; \
273         POP(t); \
274         POP(b); \
275         SETDST; \
276         stackdepth -= 2; \
277     } while (0)
278
279 #define OP2_1(s) \
280     do { \
281         REQUIRE_2; \
282         POP(s); \
283         POP(s); \
284         NEWSTACKn(s, stackdepth - 2); \
285         SETDST; \
286         stackdepth--; \
287     } while (0)
288
289 #define OP2IAT_1(s) \
290     do { \
291         REQUIRE_2; \
292         POP(TYPE_INT); \
293         POP(TYPE_ADR); \
294         NEWSTACKn(s, stackdepth - 2); \
295         SETDST; \
296         stackdepth--; \
297     } while (0)
298
299 #define OP2IT_1(s) \
300     do { \
301         REQUIRE_2; \
302         POP(TYPE_INT); \
303         POP(s); \
304         NEWSTACKn(s, stackdepth - 2); \
305         SETDST; \
306         stackdepth--; \
307     } while (0)
308
309 #define OPTT2_1(s,d) \
310     do { \
311         REQUIRE_2; \
312         POP(s); \
313         POP(s); \
314         NEWSTACKn(d, stackdepth - 2); \
315         SETDST; \
316         stackdepth--; \
317     } while (0)
318
319 #define OP2_2(s) \
320     do { \
321         REQUIRE_2; \
322         POP(s); \
323         POP(s); \
324         NEWSTACKn(s, stackdepth - 2); \
325         NEWSTACKn(s, stackdepth - 1); \
326         SETDST; \
327     } while (0)
328
329 #define OP3TIA_0(s) \
330     do { \
331         REQUIRE_3; \
332         POP(s); \
333         POP(TYPE_INT); \
334         POP(TYPE_ADR); \
335         SETDST; \
336         stackdepth -= 3; \
337     } while (0)
338
339 #define OP3_0(s) \
340     do { \
341         REQUIRE_3; \
342         POP(s); \
343         POP(s); \
344         POP(s); \
345         SETDST; \
346         stackdepth -= 3; \
347     } while (0)
348
349 #define POPMANY(i) \
350     do { \
351         REQUIRE((i)); \
352         stackdepth -= (i); \
353         while(--(i) >= 0) { \
354             POPANY; \
355         } \
356         SETDST; \
357     } while (0)
358
359 /* Do not copy Interface Stackslots over DUP! */
360 #define DUP         {REQUIRE_1; \
361                              if (CURKIND != STACKVAR) { \
362                                                  NEWSTACK(CURTYPE,CURKIND,curstack->varnum); \
363                                          } else { \
364                                                  NEWSTACK(CURTYPE, TEMPVAR, stackdepth); \
365                                          } \
366                                          SETDST; stackdepth++; INC_LIFETIMES(1);}
367 #define SWAP        {REQUIRE_2;COPY(curstack,new);POPANY;COPY(curstack,new+1);POPANY;\
368                     new[0].prev=curstack;new[1].prev=new;\
369                     curstack=new+1;new+=2;SETDST;}
370 #define DUP_X1      {REQUIRE_2;COPY(curstack,new);COPY(curstack,new+2);POPANY;\
371                     COPY(curstack,new+1);POPANY;new[0].prev=curstack;\
372                     new[1].prev=new;new[2].prev=new+1;\
373                     curstack=new+2;new+=3;SETDST;stackdepth++; INC_LIFETIMES(3);}
374 #define DUP2_X1     {REQUIRE_3;COPY(curstack,new+1);COPY(curstack,new+4);POPANY;\
375                     COPY(curstack,new);COPY(curstack,new+3);POPANY;\
376                     COPY(curstack,new+2);POPANY;new[0].prev=curstack;\
377                     new[1].prev=new;new[2].prev=new+1;\
378                     new[3].prev=new+2;new[4].prev=new+3;\
379                     curstack=new+4;new+=5;SETDST;stackdepth+=2; INC_LIFETIMES(5);}
380 #define DUP_X2      {REQUIRE_3;COPY(curstack,new);COPY(curstack,new+3);POPANY;\
381                     COPY(curstack,new+2);POPANY;COPY(curstack,new+1);POPANY;\
382                     new[0].prev=curstack;new[1].prev=new;\
383                     new[2].prev=new+1;new[3].prev=new+2;\
384                     curstack=new+3;new+=4;SETDST;stackdepth++; INC_LIFETIMES(4);}
385 #define DUP2_X2     {REQUIRE_4;COPY(curstack,new+1);COPY(curstack,new+5);POPANY;\
386                     COPY(curstack,new);COPY(curstack,new+4);POPANY;\
387                     COPY(curstack,new+3);POPANY;COPY(curstack,new+2);POPANY;\
388                     new[0].prev=curstack;new[1].prev=new;\
389                     new[2].prev=new+1;new[3].prev=new+2;\
390                     new[4].prev=new+3;new[5].prev=new+4;\
391                     curstack=new+5;new+=6;SETDST;stackdepth+=2; INC_LIFETIMES(6);}
392
393
394 /*--------------------------------------------------*/
395 /* MACROS FOR HANDLING BASIC BLOCKS                 */
396 /*--------------------------------------------------*/
397
398 /* COPYCURSTACK makes a copy of the current operand stack (curstack)
399  * and returns it in the variable copy.
400  *
401  * This macro is used to propagate the operand stack from one basic
402  * block to another. The destination block receives the copy as its
403  * input stack.
404  */
405 #define COPYCURSTACK(copy) {\
406         int d;\
407         stackptr s;\
408         if(curstack){\
409                 s=curstack;\
410                 new+=stackdepth;\
411                 d=stackdepth;\
412                 copy=new;\
413                 while(s){\
414                         copy--;d--;\
415                         copy->prev=copy-1;\
416                         copy->type=s->type;\
417                         copy->flags=0;\
418                         copy->varkind=STACKVAR;\
419                         copy->varnum=d;\
420                         s=s->prev;\
421                         }\
422                 copy->prev=NULL;\
423                 copy=new-1;\
424                 }\
425         else\
426                 copy=NULL;\
427 }
428
429 /* MARKREACHED marks the destination block <b> as reached. If this
430  * block has been reached before we check if stack depth and types
431  * match. Otherwise the destination block receives a copy of the
432  * current stack as its input stack.
433  *
434  * b...destination block
435  * c...current stack
436  */
437
438 #define MARKREACHED(b,c) \
439     do { \
440                 if ((b) <= (bptr)) \
441                         (b)->bitflags |= BBFLAG_REPLACEMENT; \
442             if ((b)->flags < BBREACHED) { \
443                     COPYCURSTACK((c)); \
444             (b)->flags = BBREACHED; \
445             (b)->instack = (c); \
446             (b)->indepth = stackdepth; \
447         } else { \
448             stackptr s = curstack; \
449             stackptr t = (b)->instack; \
450                         CHECK_STACK_DEPTH((b)->indepth, stackdepth); \
451                     while (s) { \
452                                 CHECK_BASIC_TYPE(s->type,t->type); \
453                             s = s->prev; \
454                 t = t->prev; \
455                         } \
456                 } \
457     } while (0)
458
459
460 /* function prototypes ********************************************************/
461
462 bool stack_init(void);
463
464 methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd);
465
466 void stack_print(codegendata *cd, stackptr s);
467 void show_icmd_method(methodinfo *m, codegendata *cd, registerdata *rd);
468 void show_icmd_block(methodinfo *m, codegendata *cd, basicblock *bptr);
469 void show_icmd(instruction *iptr, bool deadcode);
470
471 /* machine dependent return value handling function */
472 void md_return_alloc(methodinfo *m, registerdata *rd, s4 return_type,
473                                          stackptr stackslot);
474
475 #endif /* _STACK_H */
476
477
478 /*
479  * These are local overrides for various environment variables in Emacs.
480  * Please do not remove this and leave it at the end of the file, where
481  * Emacs will automagically detect them.
482  * ---------------------------------------------------------------------
483  * Local variables:
484  * mode: c
485  * indent-tabs-mode: t
486  * c-basic-offset: 4
487  * tab-width: 4
488  * End:
489  * vim:noexpandtab:sw=4:ts=4:
490  */