* src/vm/jit/stack.h (TYPE_VERIFYERROR): Converted most of body to a function.
[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 4482 2006-02-07 23:18:23Z 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 /* 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 *******************************************************/
186 #define COPY(s,d) \
187     do { \
188         (d)->flags = 0; \
189         (d)->type = (s)->type; \
190                 if ((s)->varkind == LOCALVAR) \
191                         (s)->varkind = TEMPVAR; \
192         (d)->varkind = (s)->varkind; \
193         (d)->varnum = (s)->varnum; \
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                             if (CURKIND == LOCALVAR) \
346                                     CURKIND = TEMPVAR; \
347                     NEWSTACK(CURTYPE,CURKIND,curstack->varnum);SETDST; \
348                     stackdepth++; INC_LIFETIMES(1);}
349 #define SWAP        {REQUIRE_2;COPY(curstack,new);POPANY;COPY(curstack,new+1);POPANY;\
350                     new[0].prev=curstack;new[1].prev=new;\
351                     curstack=new+1;new+=2;SETDST;}
352 #define DUP_X1      {REQUIRE_2;COPY(curstack,new);COPY(curstack,new+2);POPANY;\
353                     COPY(curstack,new+1);POPANY;new[0].prev=curstack;\
354                     new[1].prev=new;new[2].prev=new+1;\
355                     curstack=new+2;new+=3;SETDST;stackdepth++; INC_LIFETIMES(3);}
356 #define DUP2_X1     {REQUIRE_3;COPY(curstack,new+1);COPY(curstack,new+4);POPANY;\
357                     COPY(curstack,new);COPY(curstack,new+3);POPANY;\
358                     COPY(curstack,new+2);POPANY;new[0].prev=curstack;\
359                     new[1].prev=new;new[2].prev=new+1;\
360                     new[3].prev=new+2;new[4].prev=new+3;\
361                     curstack=new+4;new+=5;SETDST;stackdepth+=2; INC_LIFETIMES(5);}
362 #define DUP_X2      {REQUIRE_3;COPY(curstack,new);COPY(curstack,new+3);POPANY;\
363                     COPY(curstack,new+2);POPANY;COPY(curstack,new+1);POPANY;\
364                     new[0].prev=curstack;new[1].prev=new;\
365                     new[2].prev=new+1;new[3].prev=new+2;\
366                     curstack=new+3;new+=4;SETDST;stackdepth++; INC_LIFETIMES(4);}
367 #define DUP2_X2     {REQUIRE_4;COPY(curstack,new+1);COPY(curstack,new+5);POPANY;\
368                     COPY(curstack,new);COPY(curstack,new+4);POPANY;\
369                     COPY(curstack,new+3);POPANY;COPY(curstack,new+2);POPANY;\
370                     new[0].prev=curstack;new[1].prev=new;\
371                     new[2].prev=new+1;new[3].prev=new+2;\
372                     new[4].prev=new+3;new[5].prev=new+4;\
373                     curstack=new+5;new+=6;SETDST;stackdepth+=2; INC_LIFETIMES(6);}
374
375
376 /*--------------------------------------------------*/
377 /* MACROS FOR HANDLING BASIC BLOCKS                 */
378 /*--------------------------------------------------*/
379
380 /* COPYCURSTACK makes a copy of the current operand stack (curstack)
381  * and returns it in the variable copy.
382  *
383  * This macro is used to propagate the operand stack from one basic
384  * block to another. The destination block receives the copy as its
385  * input stack.
386  */
387 #define COPYCURSTACK(copy) {\
388         int d;\
389         stackptr s;\
390         if(curstack){\
391                 s=curstack;\
392                 new+=stackdepth;\
393                 d=stackdepth;\
394                 copy=new;\
395                 while(s){\
396                         copy--;d--;\
397                         copy->prev=copy-1;\
398                         copy->type=s->type;\
399                         copy->flags=0;\
400                         copy->varkind=STACKVAR;\
401                         copy->varnum=d;\
402                         s=s->prev;\
403                         }\
404                 copy->prev=NULL;\
405                 copy=new-1;\
406                 }\
407         else\
408                 copy=NULL;\
409 }
410
411 /* BBEND is called at the end of each basic block (after the last
412  * instruction of the block has been processed).
413  */
414
415
416 #if defined(ENABLE_INTRP)
417 #define IF_NO_INTRP(x) if (!opt_intrp) { x }
418 #else
419 #define IF_NO_INTRP(x) { x }
420 #endif
421
422 #define BBEND(s,i) { \
423         (i) = stackdepth - 1; \
424         copy = (s); \
425         while (copy) { \
426                 if ((copy->varkind == STACKVAR) && (copy->varnum > (i))) \
427                         copy->varkind = TEMPVAR; \
428                 else { \
429                         copy->varkind = STACKVAR; \
430                         copy->varnum = (i);\
431                 } \
432         IF_NO_INTRP(rd->interfaces[(i)][copy->type].type = copy->type; \
433                     rd->interfaces[(i)][copy->type].flags |= copy->flags;) \
434                 (i)--; copy = copy->prev; \
435         } \
436         (i) = bptr->indepth - 1; \
437         copy = bptr->instack; \
438         while (copy) { \
439         IF_NO_INTRP( \
440             rd->interfaces[(i)][copy->type].type = copy->type; \
441             if (copy->varkind == STACKVAR) { \
442                 if (copy->flags & SAVEDVAR) \
443                     rd->interfaces[(i)][copy->type].flags |= SAVEDVAR; \
444             } \
445         ) \
446                 (i)--; copy = copy->prev; \
447         } \
448 }
449
450
451 /* MARKREACHED marks the destination block <b> as reached. If this
452  * block has been reached before we check if stack depth and types
453  * match. Otherwise the destination block receives a copy of the
454  * current stack as its input stack.
455  *
456  * b...destination block
457  * c...current stack
458  */
459
460 #define MARKREACHED(b,c) \
461     do { \
462             if ((b)->flags < BBREACHED) { \
463                     COPYCURSTACK((c)); \
464             (b)->flags = BBREACHED; \
465             (b)->instack = (c); \
466             (b)->indepth = stackdepth; \
467         } else { \
468             stackptr s = curstack; \
469             stackptr t = (b)->instack; \
470                     if ((b)->indepth != stackdepth) { \
471                 *exceptionptr = new_verifyerror(m,"Stack depth mismatch"); \
472                 return NULL; \
473             } \
474                     while (s) { \
475                 if (s->type != t->type) \
476                                     TYPE_VERIFYERROR(t->type); \
477                             s = s->prev; \
478                 t = t->prev; \
479                         } \
480                 } \
481     } while (0)
482
483
484 /* function prototypes ********************************************************/
485
486 bool stack_init(void);
487
488 methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd);
489
490 void icmd_print_stack(codegendata *cd, stackptr s);
491 void show_icmd_method(methodinfo *m, codegendata *cd, registerdata *rd);
492 void show_icmd_block(methodinfo *m, codegendata *cd, basicblock *bptr);
493 void show_icmd(instruction *iptr, bool deadcode);
494
495 /* machine dependent return value handling function */
496 void md_return_alloc(methodinfo *m, registerdata *rd, s4 return_type,
497                                          stackptr stackslot);
498
499 #endif /* _STACK_H */
500
501
502 /*
503  * These are local overrides for various environment variables in Emacs.
504  * Please do not remove this and leave it at the end of the file, where
505  * Emacs will automagically detect them.
506  * ---------------------------------------------------------------------
507  * Local variables:
508  * mode: c
509  * indent-tabs-mode: t
510  * c-basic-offset: 4
511  * tab-width: 4
512  * End:
513  * vim:noexpandtab:sw=4:ts=4:
514  */