9bbef887ec7e9cf5e321e09891e59c49ed39654d
[cacao.git] / src / vm / jit / stack.h
1 /* vm/jit/stack.h - stack analysis header
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    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., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Christian Thalinger
28
29    Changes: Christian Ullrich
30
31    $Id: stack.h 3994 2005-12-22 14:00:06Z twisti $
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 /* SIGNALING ERRORS                                 */
64 /*--------------------------------------------------*/
65
66 #define TYPE_VERIFYERROR(t) \
67     do { \
68         char *type = NULL; \
69         switch ((t)) { \
70         case TYPE_INT: \
71                         type = "integer"; \
72                         break; \
73                 case TYPE_LNG: \
74                         type = "long"; \
75                         break; \
76                 case TYPE_FLT: \
77                         type = "float"; \
78                         break; \
79                 case TYPE_DBL: \
80                         type = "double"; \
81                         break; \
82                 case TYPE_ADR: \
83                         type = "object/array"; \
84                         break; \
85                 } \
86         *exceptionptr = new_verifyerror(m, \
87                                                                                 "Expecting to find %s on stack", \
88                                                                                 type); \
89         return NULL; \
90     } while (0)
91
92
93 /*--------------------------------------------------*/
94 /* STACK UNDERFLOW/OVERFLOW CHECKS                  */
95 /*--------------------------------------------------*/
96
97 /* underflow checks */
98
99 #define REQUIRE(num) \
100     do { \
101         if (stackdepth < (num)) { \
102             *exceptionptr = \
103                 new_verifyerror(m, "Unable to pop operand off an empty stack"); \
104             return NULL; \
105         } \
106     } while(0)
107
108 #define REQUIRE_1     REQUIRE(1)
109 #define REQUIRE_2     REQUIRE(2)
110 #define REQUIRE_3     REQUIRE(3)
111 #define REQUIRE_4     REQUIRE(4)
112
113
114 /* overflow check */
115 /* We allow ACONST instructions inserted as arguments to builtin
116  * functions to exceed the maximum stack depth.  Maybe we should check
117  * against maximum stack depth only at block boundaries?
118  */
119
120 #define CHECKOVERFLOW \
121         do { \
122                 if (stackdepth > m->maxstack) { \
123                         if (iptr[0].opc != ICMD_ACONST || iptr[0].op1 == 0) { \
124                 *exceptionptr = new_verifyerror(m, "Stack size too large"); \
125                 return NULL; \
126             } \
127                 } \
128         } while(0)
129
130
131 /*--------------------------------------------------*/
132 /* ALLOCATING STACK SLOTS                           */
133 /*--------------------------------------------------*/
134
135 #define NEWSTACK_(s,v,n) \
136     do { \
137         new->prev = curstack; \
138         new->type = (s); \
139         new->flags = 0; \
140         new->varkind = (v); \
141         new->varnum = (n); \
142         curstack = new; \
143         new++; \
144     } while (0)
145
146
147 /* Initialize regoff, so -sia can show regnames even before reg.inc */ 
148 /* regs[rd->intregargnum has to be set for this */ 
149 /* new->regoff = (IS_FLT_DBL_TYPE(s))?-1:rd->intreg_argnum; }*/
150
151 #define NEWSTACK(s,v,n) { NEWSTACK_(s,v,n); INC_LIFETIMES(1); }
152
153 #define NEWSTACKn(s,n)  NEWSTACK(s,UNDEFVAR,n)
154 #define NEWSTACK0(s)    NEWSTACK(s,UNDEFVAR,0)
155
156 /* allocate the input stack for an exception handler */
157 #define NEWXSTACK   {NEWSTACK(TYPE_ADR,STACKVAR,0);curstack=0;}
158
159
160 /*--------------------------------------------------*/
161 /* STACK MANIPULATION                               */
162 /*--------------------------------------------------*/
163
164 /* resetting to an empty operand stack */
165
166 #define STACKRESET \
167     do { \
168         curstack = 0; \
169         stackdepth = 0; \
170     } while (0)
171
172
173 /* set the output stack of the current instruction */
174
175 #define SETDST    iptr->dst = curstack;
176
177
178 /* The following macros do NOT check stackdepth, set stackdepth or iptr->dst */
179
180 #define POP(s) \
181     do { \
182         if ((s) != curstack->type) { \
183             TYPE_VERIFYERROR((s)); \
184         } \
185         if (curstack->varkind == UNDEFVAR) \
186             curstack->varkind = TEMPVAR; \
187         curstack = curstack->prev; \
188     } while (0)
189
190 #define POPANY \
191     do { \
192         if (curstack->varkind == UNDEFVAR) \
193             curstack->varkind = TEMPVAR; \
194         curstack = curstack->prev; \
195     } while (0)
196
197 /*******************************************************
198 Quick Fix to prevent dependence problems of local vars
199 varnum is not set to the according position within the stack
200 like it is done normaly in stack.c
201 -> if this shows to be a problem this can be solved in all the
202 DUP* and SWAP Macros
203 TODO: dependences should be prevented as described in the
204 CACAO JVM Paper
205 *******************************************************/
206 #define COPY(s,d) \
207     do { \
208         (d)->flags = 0; \
209         (d)->type = (s)->type; \
210                 if ((s)->varkind == LOCALVAR) \
211                         (s)->varkind = TEMPVAR; \
212         (d)->varkind = (s)->varkind; \
213         (d)->varnum = (s)->varnum; \
214     } while (0)
215
216
217 /*--------------------------------------------------*/
218 /* STACK OPERATIONS MODELING                        */
219 /*--------------------------------------------------*/
220
221 /* The following macros are used to model the stack manipulations of
222  * different kinds of instructions.
223  *
224  * These macros check the input stackdepth and they set the output
225  * stackdepth and the output stack of the instruction (iptr->dst).
226  *
227  * These macros do *not* check for stack overflows!
228  */
229    
230 #define PUSHCONST(s){NEWSTACKn(s,stackdepth);SETDST;stackdepth++;}
231 #define LOAD(s,v,n) {NEWSTACK(s,v,n);SETDST;stackdepth++;}
232 #define STORE(s)    {REQUIRE_1;POP(s);SETDST;stackdepth--;}
233
234 #define OP1_0(s) \
235     do { \
236         REQUIRE_1; \
237         POP(s); \
238         SETDST; \
239         stackdepth--; \
240     } while (0)
241
242 #define OP1_0ANY \
243     do { \
244         REQUIRE_1; \
245         POPANY; \
246         SETDST; \
247         stackdepth--; \
248     } while (0)
249
250 #define OP0_1(s) \
251     do { \
252         NEWSTACKn(s, stackdepth); \
253         SETDST; \
254         stackdepth++; \
255     } while (0)
256
257 #define OP1_1(s,d) \
258     do { \
259         REQUIRE_1; \
260         POP(s); \
261         NEWSTACKn(d, stackdepth - 1);\
262         SETDST; \
263     } while (0)
264
265 #define OP2_0(s) \
266     do { \
267         REQUIRE_2; \
268         POP(s); \
269         POP(s); \
270         SETDST; \
271         stackdepth -= 2; \
272     } while (0)
273
274 #define OPTT2_0(t,b) \
275     do { \
276         REQUIRE_2; \
277         POP(t); \
278         POP(b); \
279         SETDST; \
280         stackdepth -= 2; \
281     } while (0)
282
283 #define OP2_1(s) \
284     do { \
285         REQUIRE_2; \
286         POP(s); \
287         POP(s); \
288         NEWSTACKn(s, stackdepth - 2); \
289         SETDST; \
290         stackdepth--; \
291     } while (0)
292
293 #define OP2IAT_1(s) \
294     do { \
295         REQUIRE_2; \
296         POP(TYPE_INT); \
297         POP(TYPE_ADR); \
298         NEWSTACKn(s, stackdepth - 2); \
299         SETDST; \
300         stackdepth--; \
301     } while (0)
302
303 #define OP2IT_1(s) \
304     do { \
305         REQUIRE_2; \
306         POP(TYPE_INT); \
307         POP(s); \
308         NEWSTACKn(s, stackdepth - 2); \
309         SETDST; \
310         stackdepth--; \
311     } while (0)
312
313 #define OPTT2_1(s,d) \
314     do { \
315         REQUIRE_2; \
316         POP(s); \
317         POP(s); \
318         NEWSTACKn(d, stackdepth - 2); \
319         SETDST; \
320         stackdepth--; \
321     } while (0)
322
323 #define OP2_2(s) \
324     do { \
325         REQUIRE_2; \
326         POP(s); \
327         POP(s); \
328         NEWSTACKn(s, stackdepth - 2); \
329         NEWSTACKn(s, stackdepth - 1); \
330         SETDST; \
331     } while (0)
332
333 #define OP3TIA_0(s) \
334     do { \
335         REQUIRE_3; \
336         POP(s); \
337         POP(TYPE_INT); \
338         POP(TYPE_ADR); \
339         SETDST; \
340         stackdepth -= 3; \
341     } while (0)
342
343 #define OP3_0(s) \
344     do { \
345         REQUIRE_3; \
346         POP(s); \
347         POP(s); \
348         POP(s); \
349         SETDST; \
350         stackdepth -= 3; \
351     } while (0)
352
353 #define POPMANY(i) \
354     do { \
355         REQUIRE((i)); \
356         stackdepth -= (i); \
357         while(--(i) >= 0) { \
358             POPANY; \
359         } \
360         SETDST; \
361     } while (0)
362
363 /* Same dependency quick fix as at COPY */
364 #define DUP         {REQUIRE_1; \
365                             if (CURKIND == LOCALVAR) \
366                                     CURKIND = TEMPVAR; \
367                     NEWSTACK(CURTYPE,CURKIND,curstack->varnum);SETDST; \
368                     stackdepth++; INC_LIFETIMES(1);}
369 #define SWAP        {REQUIRE_2;COPY(curstack,new);POPANY;COPY(curstack,new+1);POPANY;\
370                     new[0].prev=curstack;new[1].prev=new;\
371                     curstack=new+1;new+=2;SETDST;}
372 #define DUP_X1      {REQUIRE_2;COPY(curstack,new);COPY(curstack,new+2);POPANY;\
373                     COPY(curstack,new+1);POPANY;new[0].prev=curstack;\
374                     new[1].prev=new;new[2].prev=new+1;\
375                     curstack=new+2;new+=3;SETDST;stackdepth++; INC_LIFETIMES(3);}
376 #define DUP2_X1     {REQUIRE_3;COPY(curstack,new+1);COPY(curstack,new+4);POPANY;\
377                     COPY(curstack,new);COPY(curstack,new+3);POPANY;\
378                     COPY(curstack,new+2);POPANY;new[0].prev=curstack;\
379                     new[1].prev=new;new[2].prev=new+1;\
380                     new[3].prev=new+2;new[4].prev=new+3;\
381                     curstack=new+4;new+=5;SETDST;stackdepth+=2; INC_LIFETIMES(5);}
382 #define DUP_X2      {REQUIRE_3;COPY(curstack,new);COPY(curstack,new+3);POPANY;\
383                     COPY(curstack,new+2);POPANY;COPY(curstack,new+1);POPANY;\
384                     new[0].prev=curstack;new[1].prev=new;\
385                     new[2].prev=new+1;new[3].prev=new+2;\
386                     curstack=new+3;new+=4;SETDST;stackdepth++; INC_LIFETIMES(4);}
387 #define DUP2_X2     {REQUIRE_4;COPY(curstack,new+1);COPY(curstack,new+5);POPANY;\
388                     COPY(curstack,new);COPY(curstack,new+4);POPANY;\
389                     COPY(curstack,new+3);POPANY;COPY(curstack,new+2);POPANY;\
390                     new[0].prev=curstack;new[1].prev=new;\
391                     new[2].prev=new+1;new[3].prev=new+2;\
392                     new[4].prev=new+3;new[5].prev=new+4;\
393                     curstack=new+5;new+=6;SETDST;stackdepth+=2; INC_LIFETIMES(6);}
394
395
396 /*--------------------------------------------------*/
397 /* MACROS FOR HANDLING BASIC BLOCKS                 */
398 /*--------------------------------------------------*/
399
400 /* COPYCURSTACK makes a copy of the current operand stack (curstack)
401  * and returns it in the variable copy.
402  *
403  * This macro is used to propagate the operand stack from one basic
404  * block to another. The destination block receives the copy as its
405  * input stack.
406  */
407 #define COPYCURSTACK(copy) {\
408         int d;\
409         stackptr s;\
410         if(curstack){\
411                 s=curstack;\
412                 new+=stackdepth;\
413                 d=stackdepth;\
414                 copy=new;\
415                 while(s){\
416                         copy--;d--;\
417                         copy->prev=copy-1;\
418                         copy->type=s->type;\
419                         copy->flags=0;\
420                         copy->varkind=STACKVAR;\
421                         copy->varnum=d;\
422                         s=s->prev;\
423                         }\
424                 copy->prev=NULL;\
425                 copy=new-1;\
426                 }\
427         else\
428                 copy=NULL;\
429 }
430
431 /* BBEND is called at the end of each basic block (after the last
432  * instruction of the block has been processed).
433  */
434
435
436 #if defined(ENABLE_INTRP)
437 #define IF_NO_INTRP(x) if (!opt_intrp) { x }
438 #else
439 #define IF_NO_INTRP(x) { x }
440 #endif
441
442 #define BBEND(s,i) { \
443         (i) = stackdepth - 1; \
444         copy = (s); \
445         while (copy) { \
446                 if ((copy->varkind == STACKVAR) && (copy->varnum > (i))) \
447                         copy->varkind = TEMPVAR; \
448                 else { \
449                         copy->varkind = STACKVAR; \
450                         copy->varnum = (i);\
451                 } \
452         IF_NO_INTRP(rd->interfaces[(i)][copy->type].type = copy->type; \
453                     rd->interfaces[(i)][copy->type].flags |= copy->flags;) \
454                 (i)--; copy = copy->prev; \
455         } \
456         (i) = bptr->indepth - 1; \
457         copy = bptr->instack; \
458         while (copy) { \
459         IF_NO_INTRP( \
460             rd->interfaces[(i)][copy->type].type = copy->type; \
461             if (copy->varkind == STACKVAR) { \
462                 if (copy->flags & SAVEDVAR) \
463                     rd->interfaces[(i)][copy->type].flags |= SAVEDVAR; \
464             } \
465         ) \
466                 (i)--; copy = copy->prev; \
467         } \
468 }
469
470
471 /* MARKREACHED marks the destination block <b> as reached. If this
472  * block has been reached before we check if stack depth and types
473  * match. Otherwise the destination block receives a copy of the
474  * current stack as its input stack.
475  *
476  * b...destination block
477  * c...current stack
478  */
479
480 #define MARKREACHED(b,c) \
481     do { \
482             if ((b)->flags < 0) { \
483                     COPYCURSTACK((c)); \
484             (b)->flags = 0; \
485             (b)->instack = (c); \
486             (b)->indepth = stackdepth; \
487         } else { \
488             stackptr s = curstack; \
489             stackptr t = (b)->instack; \
490                     if ((b)->indepth != stackdepth) { \
491                 *exceptionptr = new_verifyerror(m,"Stack depth mismatch"); \
492                 return NULL; \
493             } \
494                     while (s) { \
495                 if (s->type != t->type) \
496                                     TYPE_VERIFYERROR(t->type); \
497                             s = s->prev; \
498                 t = t->prev; \
499                         } \
500                 } \
501     } while (0)
502
503
504 /* function prototypes ********************************************************/
505
506 bool stack_init(void);
507
508 methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd);
509
510 void icmd_print_stack(codegendata *cd, stackptr s);
511 void show_icmd_method(methodinfo *m, codegendata *cd, registerdata *rd);
512 void show_icmd_block(methodinfo *m, codegendata *cd, basicblock *bptr);
513 void show_icmd(instruction *iptr, bool deadcode);
514
515 /* machine dependent return value handling function */
516 void md_return_alloc(methodinfo *m, registerdata *rd, s4 return_type,
517                                          stackptr stackslot);
518
519 #endif /* _STACK_H */
520
521
522 /*
523  * These are local overrides for various environment variables in Emacs.
524  * Please do not remove this and leave it at the end of the file, where
525  * Emacs will automagically detect them.
526  * ---------------------------------------------------------------------
527  * Local variables:
528  * mode: c
529  * indent-tabs-mode: t
530  * c-basic-offset: 4
531  * tab-width: 4
532  * End:
533  */