* src/vm/jit/stack.h: Removed code for old instruction format.
[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 5303 2006-09-05 10:39:58Z 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 /* convenient abbreviations */
52 #define CURKIND    curstack->varkind
53 #define CURTYPE    curstack->type
54
55
56 /*--------------------------------------------------*/
57 /* STACK DEPTH CHECKING                             */
58 /*--------------------------------------------------*/
59
60 #if defined(ENABLE_VERIFIER)
61 #define CHECK_STACK_DEPTH(depthA,depthB) \
62         do { \
63                 if ((depthA) != (depthB)) \
64                         goto throw_stack_depth_error; \
65         } while (0)
66 #else /* !ENABLE_VERIFIER */
67 #define CHECK_STACK_DEPTH(depthA,depthB)
68 #endif /* ENABLE_VERIFIER */
69
70
71 /*--------------------------------------------------*/
72 /* BASIC TYPE CHECKING                              */
73 /*--------------------------------------------------*/
74
75 /* XXX would be nice if we did not have to pass the expected type */
76
77 #if defined(ENABLE_VERIFIER)
78 #define CHECK_BASIC_TYPE(expected,actual) \
79         do { \
80                 if ((actual) != (expected)) { \
81                         expectedtype = (expected); \
82                         goto throw_stack_type_error; \
83                 } \
84         } while (0)
85 #else /* !ENABLE_VERIFIER */
86 #define CHECK_BASIC_TYPE(expected,actual)
87 #endif /* ENABLE_VERIFIER */
88
89 /*--------------------------------------------------*/
90 /* STACK UNDERFLOW/OVERFLOW CHECKS                  */
91 /*--------------------------------------------------*/
92
93 /* underflow checks */
94
95 #if defined(ENABLE_VERIFIER)
96 #define REQUIRE(num) \
97     do { \
98         if (stackdepth < (num)) \
99                         goto throw_stack_underflow; \
100         } while (0)
101 #else /* !ENABLE_VERIFIER */
102 #define REQUIRE(num)
103 #endif /* ENABLE_VERIFIER */
104
105 #define REQUIRE_1     REQUIRE(1)
106 #define REQUIRE_2     REQUIRE(2)
107 #define REQUIRE_3     REQUIRE(3)
108 #define REQUIRE_4     REQUIRE(4)
109
110
111 /* overflow check */
112 /* We allow ACONST instructions inserted as arguments to builtin
113  * functions to exceed the maximum stack depth.  Maybe we should check
114  * against maximum stack depth only at block boundaries?
115  */
116
117 /* XXX we should find a way to remove the opc/op1 check */
118 #if defined(ENABLE_VERIFIER)
119 #define NEW_CHECKOVERFLOW \
120         do { \
121                 if (stackdepth > m->maxstack) \
122                         if ((iptr->opc != ICMD_ACONST) || !(iptr->flags.bits & INS_FLAG_NOCHECK)) \
123                                 goto throw_stack_overflow; \
124         } while(0)
125 #else /* !ENABLE_VERIFIER */
126 #define NEW_CHECKOVERFLOW
127 #endif /* ENABLE_VERIFIER */
128
129 /* XXX we should find a way to remove the opc/op1 check */
130 #if defined(ENABLE_VERIFIER)
131 #define CHECKOVERFLOW \
132         do { \
133                 if (stackdepth > m->maxstack) \
134                         if ((iptr[0].opc != ICMD_ACONST) || (iptr[0].op1 == 0)) \
135                                 goto throw_stack_overflow; \
136         } while(0)
137 #else /* !ENABLE_VERIFIER */
138 #define CHECKOVERFLOW
139 #endif /* ENABLE_VERIFIER */
140
141 /*--------------------------------------------------*/
142 /* ALLOCATING STACK SLOTS                           */
143 /*--------------------------------------------------*/
144
145 #define NEWSTACK(s,v,n) \
146     do { \
147         new->prev = curstack; \
148         new->type = (s); \
149         new->flags = 0; \
150         new->varkind = (v); \
151         new->varnum = (n); \
152         curstack = new; \
153         new++; \
154     } while (0)
155
156 /* Initialize regoff, so -sia can show regnames even before reg.inc */
157 /* regs[rd->intregargnum] has to be set for this                    */
158 /* new->regoff = (IS_FLT_DBL_TYPE(s))?-1:rd->intreg_argnum; }       */
159
160 #define NEWSTACKn(s,n)  NEWSTACK(s,UNDEFVAR,n)
161 #define NEWSTACK0(s)    NEWSTACK(s,UNDEFVAR,0)
162
163 /* allocate the input stack for an exception handler */
164 #define NEWXSTACK   {NEWSTACK(TYPE_ADR,STACKVAR,0);curstack=0;}
165
166
167 /*--------------------------------------------------*/
168 /* STACK MANIPULATION                               */
169 /*--------------------------------------------------*/
170
171 /* resetting to an empty operand stack */
172
173 #define STACKRESET \
174     do { \
175         curstack = 0; \
176         stackdepth = 0; \
177     } while (0)
178
179
180 /* set the output stack of the current instruction */
181
182 #define SETDST    iptr->dst = curstack;
183
184
185 /* The following macros do NOT check stackdepth, set stackdepth or iptr->dst */
186
187 #define POP(s) \
188     do { \
189                 CHECK_BASIC_TYPE((s),curstack->type); \
190         if (curstack->varkind == UNDEFVAR) \
191             curstack->varkind = TEMPVAR; \
192         curstack = curstack->prev; \
193     } while (0)
194
195 #define POPANY \
196     do { \
197         if (curstack->varkind == UNDEFVAR) \
198             curstack->varkind = TEMPVAR; \
199         curstack = curstack->prev; \
200     } while (0)
201
202 /* Do not copy Interface Stackslots over DUPx, Swaps! */
203 #define COPY(s,d) \
204     do { \
205         (d)->flags = 0; \
206         (d)->type = (s)->type; \
207                 if ( (s)->varkind != STACKVAR) {                \
208                         (d)->varkind = (s)->varkind; \
209                         (d)->varnum = (s)->varnum;       \
210                 } else { \
211                         (d)->varkind = TEMPVAR; \
212                         (d)->varnum = 0; \
213                 } \
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 /* Do not copy Interface Stackslots over DUP! */
364 #define DUP         {REQUIRE_1; \
365                              if (CURKIND != STACKVAR) { \
366                                                  NEWSTACK(CURTYPE,CURKIND,curstack->varnum); \
367                                          } else { \
368                                                  NEWSTACK(CURTYPE, TEMPVAR, stackdepth); \
369                                          } \
370                                          SETDST; stackdepth++;}
371 #define SWAP        {REQUIRE_2;COPY(curstack,new);POPANY;COPY(curstack,new+1);POPANY;\
372                     new[0].prev=curstack;new[1].prev=new;\
373                     curstack=new+1;new+=2;SETDST;}
374 #define DUP_X1      {REQUIRE_2;COPY(curstack,new);COPY(curstack,new+2);POPANY;\
375                     COPY(curstack,new+1);POPANY;new[0].prev=curstack;\
376                     new[1].prev=new;new[2].prev=new+1;\
377                     curstack=new+2;new+=3;SETDST;stackdepth++;}
378 #define DUP2_X1     {REQUIRE_3;COPY(curstack,new+1);COPY(curstack,new+4);POPANY;\
379                     COPY(curstack,new);COPY(curstack,new+3);POPANY;\
380                     COPY(curstack,new+2);POPANY;new[0].prev=curstack;\
381                     new[1].prev=new;new[2].prev=new+1;\
382                     new[3].prev=new+2;new[4].prev=new+3;\
383                     curstack=new+4;new+=5;SETDST;stackdepth+=2;}
384 #define DUP_X2      {REQUIRE_3;COPY(curstack,new);COPY(curstack,new+3);POPANY;\
385                     COPY(curstack,new+2);POPANY;COPY(curstack,new+1);POPANY;\
386                     new[0].prev=curstack;new[1].prev=new;\
387                     new[2].prev=new+1;new[3].prev=new+2;\
388                     curstack=new+3;new+=4;SETDST;stackdepth++;}
389 #define DUP2_X2     {REQUIRE_4;COPY(curstack,new+1);COPY(curstack,new+5);POPANY;\
390                     COPY(curstack,new);COPY(curstack,new+4);POPANY;\
391                     COPY(curstack,new+3);POPANY;COPY(curstack,new+2);POPANY;\
392                     new[0].prev=curstack;new[1].prev=new;\
393                     new[2].prev=new+1;new[3].prev=new+2;\
394                     new[4].prev=new+3;new[5].prev=new+4;\
395                     curstack=new+5;new+=6;SETDST;stackdepth+=2;}
396
397
398 /*--------------------------------------------------*/
399 /* MACROS FOR HANDLING BASIC BLOCKS                 */
400 /*--------------------------------------------------*/
401
402 /* COPYCURSTACK makes a copy of the current operand stack (curstack)
403  * and returns it in the variable copy.
404  *
405  * This macro is used to propagate the operand stack from one basic
406  * block to another. The destination block receives the copy as its
407  * input stack.
408  */
409 #define COPYCURSTACK(copy) {\
410         int d;\
411         stackptr s;\
412         if(curstack){\
413                 s=curstack;\
414                 new+=stackdepth;\
415                 d=stackdepth;\
416                 copy=new;\
417                 while(s){\
418                         copy--;d--;\
419                         copy->prev=copy-1;\
420                         copy->type=s->type;\
421                         copy->flags=0;\
422                         copy->varkind=STACKVAR;\
423                         copy->varnum=d;\
424                         s=s->prev;\
425                         }\
426                 copy->prev=NULL;\
427                 copy=new-1;\
428                 }\
429         else\
430                 copy=NULL;\
431 }
432
433 /* MARKREACHED marks the destination block <b> as reached. If this
434  * block has been reached before we check if stack depth and types
435  * match. Otherwise the destination block receives a copy of the
436  * current stack as its input stack.
437  *
438  * b...destination block
439  * c...current stack
440  */
441
442 #define MARKREACHED(b,c) \
443     do { \
444                 if ((b) <= (bptr)) \
445                         (b)->bitflags |= BBFLAG_REPLACEMENT; \
446             if ((b)->flags < BBREACHED) { \
447                     COPYCURSTACK((c)); \
448             (b)->flags = BBREACHED; \
449             (b)->instack = (c); \
450             (b)->indepth = stackdepth; \
451         } else { \
452             stackptr s = curstack; \
453             stackptr t = (b)->instack; \
454                         CHECK_STACK_DEPTH((b)->indepth, stackdepth); \
455                     while (s) { \
456                                 CHECK_BASIC_TYPE(s->type,t->type); \
457                             s = s->prev; \
458                 t = t->prev; \
459                         } \
460                 } \
461     } while (0)
462
463
464 /* function prototypes ********************************************************/
465
466 bool stack_init(void);
467
468 bool new_stack_analyse(jitdata *jd);
469
470 #endif /* _STACK_H */
471
472
473 /*
474  * These are local overrides for various environment variables in Emacs.
475  * Please do not remove this and leave it at the end of the file, where
476  * Emacs will automagically detect them.
477  * ---------------------------------------------------------------------
478  * Local variables:
479  * mode: c
480  * indent-tabs-mode: t
481  * c-basic-offset: 4
482  * tab-width: 4
483  * End:
484  * vim:noexpandtab:sw=4:ts=4:
485  */