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