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