* src/vm/jit/stack.h (COPY): Prevent setting varkind to STACKVAR for stackslots copie...
[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 4524 2006-02-16 19:39:36Z 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 /* Do not copy Interface Stackslots over DUPx, Swaps! */
178 #define COPY(s,d) \
179     do { \
180         (d)->flags = 0; \
181         (d)->type = (s)->type; \
182                 if ( (s)->varkind != STACKVAR) {                \
183                         (d)->varkind = (s)->varkind; \
184                         (d)->varnum = (s)->varnum;       \
185                 } else { \
186                         (d)->varkind = TEMPVAR; \
187                         (d)->varnum = 0; \
188                 } \
189     } while (0)
190
191
192 /*--------------------------------------------------*/
193 /* STACK OPERATIONS MODELING                        */
194 /*--------------------------------------------------*/
195
196 /* The following macros are used to model the stack manipulations of
197  * different kinds of instructions.
198  *
199  * These macros check the input stackdepth and they set the output
200  * stackdepth and the output stack of the instruction (iptr->dst).
201  *
202  * These macros do *not* check for stack overflows!
203  */
204    
205 #define PUSHCONST(s){NEWSTACKn(s,stackdepth);SETDST;stackdepth++;}
206 #define LOAD(s,v,n) {NEWSTACK(s,v,n);SETDST;stackdepth++;}
207 #define STORE(s)    {REQUIRE_1;POP(s);SETDST;stackdepth--;}
208
209 #define OP1_0(s) \
210     do { \
211         REQUIRE_1; \
212         POP(s); \
213         SETDST; \
214         stackdepth--; \
215     } while (0)
216
217 #define OP1_0ANY \
218     do { \
219         REQUIRE_1; \
220         POPANY; \
221         SETDST; \
222         stackdepth--; \
223     } while (0)
224
225 #define OP0_1(s) \
226     do { \
227         NEWSTACKn(s, stackdepth); \
228         SETDST; \
229         stackdepth++; \
230     } while (0)
231
232 #define OP1_1(s,d) \
233     do { \
234         REQUIRE_1; \
235         POP(s); \
236         NEWSTACKn(d, stackdepth - 1);\
237         SETDST; \
238     } while (0)
239
240 #define OP2_0(s) \
241     do { \
242         REQUIRE_2; \
243         POP(s); \
244         POP(s); \
245         SETDST; \
246         stackdepth -= 2; \
247     } while (0)
248
249 #define OPTT2_0(t,b) \
250     do { \
251         REQUIRE_2; \
252         POP(t); \
253         POP(b); \
254         SETDST; \
255         stackdepth -= 2; \
256     } while (0)
257
258 #define OP2_1(s) \
259     do { \
260         REQUIRE_2; \
261         POP(s); \
262         POP(s); \
263         NEWSTACKn(s, stackdepth - 2); \
264         SETDST; \
265         stackdepth--; \
266     } while (0)
267
268 #define OP2IAT_1(s) \
269     do { \
270         REQUIRE_2; \
271         POP(TYPE_INT); \
272         POP(TYPE_ADR); \
273         NEWSTACKn(s, stackdepth - 2); \
274         SETDST; \
275         stackdepth--; \
276     } while (0)
277
278 #define OP2IT_1(s) \
279     do { \
280         REQUIRE_2; \
281         POP(TYPE_INT); \
282         POP(s); \
283         NEWSTACKn(s, stackdepth - 2); \
284         SETDST; \
285         stackdepth--; \
286     } while (0)
287
288 #define OPTT2_1(s,d) \
289     do { \
290         REQUIRE_2; \
291         POP(s); \
292         POP(s); \
293         NEWSTACKn(d, stackdepth - 2); \
294         SETDST; \
295         stackdepth--; \
296     } while (0)
297
298 #define OP2_2(s) \
299     do { \
300         REQUIRE_2; \
301         POP(s); \
302         POP(s); \
303         NEWSTACKn(s, stackdepth - 2); \
304         NEWSTACKn(s, stackdepth - 1); \
305         SETDST; \
306     } while (0)
307
308 #define OP3TIA_0(s) \
309     do { \
310         REQUIRE_3; \
311         POP(s); \
312         POP(TYPE_INT); \
313         POP(TYPE_ADR); \
314         SETDST; \
315         stackdepth -= 3; \
316     } while (0)
317
318 #define OP3_0(s) \
319     do { \
320         REQUIRE_3; \
321         POP(s); \
322         POP(s); \
323         POP(s); \
324         SETDST; \
325         stackdepth -= 3; \
326     } while (0)
327
328 #define POPMANY(i) \
329     do { \
330         REQUIRE((i)); \
331         stackdepth -= (i); \
332         while(--(i) >= 0) { \
333             POPANY; \
334         } \
335         SETDST; \
336     } while (0)
337
338 /* Do not copy Interface Stackslots over DUP! */
339 #define DUP         {REQUIRE_1; \
340                              if (CURKIND != STACKVAR) { \
341                                                  NEWSTACK(CURTYPE,CURKIND,curstack->varnum); \
342                                          } else { \
343                                                  NEWSTACK(CURTYPE, TEMPVAR, stackdepth); \
344                                          } \
345                                          SETDST; stackdepth++; INC_LIFETIMES(1);}
346 #define SWAP        {REQUIRE_2;COPY(curstack,new);POPANY;COPY(curstack,new+1);POPANY;\
347                     new[0].prev=curstack;new[1].prev=new;\
348                     curstack=new+1;new+=2;SETDST;}
349 #define DUP_X1      {REQUIRE_2;COPY(curstack,new);COPY(curstack,new+2);POPANY;\
350                     COPY(curstack,new+1);POPANY;new[0].prev=curstack;\
351                     new[1].prev=new;new[2].prev=new+1;\
352                     curstack=new+2;new+=3;SETDST;stackdepth++; INC_LIFETIMES(3);}
353 #define DUP2_X1     {REQUIRE_3;COPY(curstack,new+1);COPY(curstack,new+4);POPANY;\
354                     COPY(curstack,new);COPY(curstack,new+3);POPANY;\
355                     COPY(curstack,new+2);POPANY;new[0].prev=curstack;\
356                     new[1].prev=new;new[2].prev=new+1;\
357                     new[3].prev=new+2;new[4].prev=new+3;\
358                     curstack=new+4;new+=5;SETDST;stackdepth+=2; INC_LIFETIMES(5);}
359 #define DUP_X2      {REQUIRE_3;COPY(curstack,new);COPY(curstack,new+3);POPANY;\
360                     COPY(curstack,new+2);POPANY;COPY(curstack,new+1);POPANY;\
361                     new[0].prev=curstack;new[1].prev=new;\
362                     new[2].prev=new+1;new[3].prev=new+2;\
363                     curstack=new+3;new+=4;SETDST;stackdepth++; INC_LIFETIMES(4);}
364 #define DUP2_X2     {REQUIRE_4;COPY(curstack,new+1);COPY(curstack,new+5);POPANY;\
365                     COPY(curstack,new);COPY(curstack,new+4);POPANY;\
366                     COPY(curstack,new+3);POPANY;COPY(curstack,new+2);POPANY;\
367                     new[0].prev=curstack;new[1].prev=new;\
368                     new[2].prev=new+1;new[3].prev=new+2;\
369                     new[4].prev=new+3;new[5].prev=new+4;\
370                     curstack=new+5;new+=6;SETDST;stackdepth+=2; INC_LIFETIMES(6);}
371
372
373 /*--------------------------------------------------*/
374 /* MACROS FOR HANDLING BASIC BLOCKS                 */
375 /*--------------------------------------------------*/
376
377 /* COPYCURSTACK makes a copy of the current operand stack (curstack)
378  * and returns it in the variable copy.
379  *
380  * This macro is used to propagate the operand stack from one basic
381  * block to another. The destination block receives the copy as its
382  * input stack.
383  */
384 #define COPYCURSTACK(copy) {\
385         int d;\
386         stackptr s;\
387         if(curstack){\
388                 s=curstack;\
389                 new+=stackdepth;\
390                 d=stackdepth;\
391                 copy=new;\
392                 while(s){\
393                         copy--;d--;\
394                         copy->prev=copy-1;\
395                         copy->type=s->type;\
396                         copy->flags=0;\
397                         copy->varkind=STACKVAR;\
398                         copy->varnum=d;\
399                         s=s->prev;\
400                         }\
401                 copy->prev=NULL;\
402                 copy=new-1;\
403                 }\
404         else\
405                 copy=NULL;\
406 }
407
408 /* BBEND is called at the end of each basic block (after the last
409  * instruction of the block has been processed).
410  */
411
412
413 #if defined(ENABLE_INTRP)
414 #define IF_NO_INTRP(x) if (!opt_intrp) { x }
415 #else
416 #define IF_NO_INTRP(x) { x }
417 #endif
418
419 #define BBEND(s,i) { \
420         (i) = stackdepth - 1; \
421         copy = (s); \
422         while (copy) { \
423                 if ((copy->varkind == STACKVAR) && (copy->varnum > (i))) \
424                         copy->varkind = TEMPVAR; \
425                 else { \
426                         copy->varkind = STACKVAR; \
427                         copy->varnum = (i);\
428                 } \
429         IF_NO_INTRP(rd->interfaces[(i)][copy->type].type = copy->type; \
430                     rd->interfaces[(i)][copy->type].flags |= copy->flags;) \
431                 (i)--; copy = copy->prev; \
432         } \
433         (i) = bptr->indepth - 1; \
434         copy = bptr->instack; \
435         while (copy) { \
436         IF_NO_INTRP( \
437             rd->interfaces[(i)][copy->type].type = copy->type; \
438             if (copy->varkind == STACKVAR) { \
439                 if (copy->flags & SAVEDVAR) \
440                     rd->interfaces[(i)][copy->type].flags |= SAVEDVAR; \
441             } \
442         ) \
443                 (i)--; copy = copy->prev; \
444         } \
445 }
446
447
448 /* MARKREACHED marks the destination block <b> as reached. If this
449  * block has been reached before we check if stack depth and types
450  * match. Otherwise the destination block receives a copy of the
451  * current stack as its input stack.
452  *
453  * b...destination block
454  * c...current stack
455  */
456
457 #define MARKREACHED(b,c) \
458     do { \
459             if ((b)->flags < BBREACHED) { \
460                     COPYCURSTACK((c)); \
461             (b)->flags = BBREACHED; \
462             (b)->instack = (c); \
463             (b)->indepth = stackdepth; \
464         } else { \
465             stackptr s = curstack; \
466             stackptr t = (b)->instack; \
467                     if ((b)->indepth != stackdepth) { \
468                 *exceptionptr = new_verifyerror(m,"Stack depth mismatch"); \
469                 return NULL; \
470             } \
471                     while (s) { \
472                 if (s->type != t->type) \
473                                     TYPE_VERIFYERROR(t->type); \
474                             s = s->prev; \
475                 t = t->prev; \
476                         } \
477                 } \
478     } while (0)
479
480
481 /* function prototypes ********************************************************/
482
483 bool stack_init(void);
484
485 methodinfo *analyse_stack(methodinfo *m, codegendata *cd, registerdata *rd);
486
487 void icmd_print_stack(codegendata *cd, stackptr s);
488 void show_icmd_method(methodinfo *m, codegendata *cd, registerdata *rd);
489 void show_icmd_block(methodinfo *m, codegendata *cd, basicblock *bptr);
490 void show_icmd(instruction *iptr, bool deadcode);
491
492 /* machine dependent return value handling function */
493 void md_return_alloc(methodinfo *m, registerdata *rd, s4 return_type,
494                                          stackptr stackslot);
495
496 #endif /* _STACK_H */
497
498
499 /*
500  * These are local overrides for various environment variables in Emacs.
501  * Please do not remove this and leave it at the end of the file, where
502  * Emacs will automagically detect them.
503  * ---------------------------------------------------------------------
504  * Local variables:
505  * mode: c
506  * indent-tabs-mode: t
507  * c-basic-offset: 4
508  * tab-width: 4
509  * End:
510  * vim:noexpandtab:sw=4:ts=4:
511  */