b978516b5f6a33422dbcbfab09b5c6b62908d07b
[cacao.git] / src / vm / jit / verify / typecheck-stackbased.c
1 /* src/vm/jit/verify/typecheck-stackbased.c - stack-based verifier
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29
30 #include "vm/types.h"
31
32 #include "vm/jit/builtin.hpp"
33 #include "mm/memory.h"
34
35 #include "vm/array.hpp"
36 #include "vm/exceptions.hpp"
37 #include "vm/global.h"
38 #include "vm/globals.hpp"
39 #include "vm/primitive.hpp"
40
41 #include "vm/jit/parse.h"
42 #include "vm/jit/show.hpp"
43 #include "vm/jit/stack.h"
44 #include "vm/jit/verify/typecheck-common.h"
45
46
47 /* this #if runs over the whole file: */
48 #if defined(ENABLE_VERIFIER)
49
50 typedef typedescriptor_t verifier_slot_t;
51
52 #if defined(TYPECHECK_VERBOSE)
53 static void typecheck_stackbased_show_state(verifier_state *state,
54                                                                                         typedescriptor *stack,
55                                                                                         typedescriptor *stackfloor,
56                                                                                         bool showins);
57 #endif
58
59
60 #define CHECK_STACK_DEPTH(d)                                         \
61     if (((u1*)stack - (u1*)stackfloor)                               \
62             < (((d)-1) * (int)sizeof(verifier_slot_t)))              \
63         goto throw_stack_underflow;
64
65 /* XXX don't need to check against ACONST for every ICMD */
66 #define CHECK_STACK_SPACE(d)                                         \
67     if (((u1*)STATE->stackceiling - (u1*)stack)                      \
68             < (((d)+1) * (int)sizeof(verifier_slot_t)))              \
69         if (STATE->iptr->opc != ICMD_ACONST                          \
70                 || INSTRUCTION_MUST_CHECK(STATE->iptr))              \
71             goto throw_stack_overflow;
72
73 #define CHECK_STACK_TYPE(s, t)                                       \
74     if ((s).type != (t))                                             \
75         goto throw_stack_type_error;
76
77 /* XXX inefficient */
78 #define CHECK_LOCAL_TYPE(index, t)                                   \
79     do {                                                             \
80         if (state.locals[(index)].type != (t))                       \
81             goto throw_local_type_error;                             \
82         if (STATE->topjsr)                                           \
83             STATE->topjsr->usedlocals[(index)] = 1;                  \
84         if (STATE->topjsr && IS_2_WORD_TYPE(t))                      \
85             STATE->topjsr->usedlocals[(index) + 1] = 1;              \
86     } while(0)
87
88 /* XXX inefficient */
89 #define STORE_LOCAL(t, index)                                        \
90     do {                                                             \
91         state.locals[(index)].type = (t);                            \
92         if ((index) && IS_2_WORD_TYPE(state.locals[(index)-1].type)) \
93             state.locals[(index-1)].type = TYPE_VOID;                \
94         if (STATE->topjsr)                                           \
95             STATE->topjsr->usedlocals[(index)] = 1;                  \
96     } while (0)
97
98 /* XXX inefficient */
99 #define STORE_LOCAL_2_WORD(t, index)                                 \
100     do {                                                             \
101         STORE_LOCAL(t, index);                                       \
102         state.locals[(index)+1].type = TYPE_VOID;                    \
103         if (STATE->topjsr)                                           \
104             STATE->topjsr->usedlocals[(index)] = 1;                  \
105     } while (0)
106
107 #define VERIFY_ERROR(msg)                                            \
108     do {                                                             \
109         LOG1("VerifyError: %s", msg);                                \
110         exceptions_throw_verifyerror(STATE->m, msg);                 \
111         return false;                                                \
112     } while (0)
113
114 #define IS_CAT1(slot)                                                \
115     ((slot).type != TYPE_VOID && !IS_2_WORD_TYPE((slot).type))
116
117 #define IS_CAT2(slot)                                                \
118     ((slot).type != TYPE_VOID && IS_2_WORD_TYPE((slot).type))
119
120 #define CHECK_CAT1(slot)                                             \
121     do {                                                             \
122         if (!IS_CAT1(slot))                                          \
123             goto throw_stack_category_error;                         \
124     } while (0)
125
126 #define CHECK_CAT2(slot)                                             \
127     do {                                                             \
128         if (!IS_CAT2(slot))                                          \
129             goto throw_stack_category_error;                         \
130     } while (0)
131
132 #define COPY_SLOT(s, d)                                              \
133     do { (d) = (s); } while (0)
134
135 #define REACH_BLOCK(target)                                          \
136     do {                                                             \
137         if (!typecheck_stackbased_reach(STATE, (target), stack,      \
138                     (stack - stackfloor) + 1))                       \
139             return false;                                            \
140     } while (0)
141
142 #define REACH(target)                                                \
143     do {                                                             \
144         REACH_BLOCK((target).block);                                 \
145     } while (0)
146
147 #undef TYPECHECK_INT
148 #undef TYPECHECK_LNG
149 #undef TYPECHECK_FLT
150 #undef TYPECHECK_DBL
151 #undef TYPECHECK_ADR
152
153 /* XXX should reuse typevector code */
154 static typecheck_result typecheck_stackbased_merge_locals(methodinfo *m,
155                                                                                                                   typedescriptor_t *dst,
156                                                                                                                   typedescriptor_t *y,
157                                                                                                                   int size)
158 {
159         bool changed = false;
160         typecheck_result r;
161
162         typedescriptor_t *a = dst;
163         typedescriptor_t *b = y;
164         while (size--) {
165                 if (a->type != TYPE_VOID && a->type != b->type) {
166                         a->type = TYPE_VOID;
167                         changed = true;
168                 }
169                 else if (a->type == TYPE_ADR) {
170                         if (TYPEINFO_IS_PRIMITIVE(a->typeinfo)) {
171                                 /* 'a' is a returnAddress */
172                                 if (!TYPEINFO_IS_PRIMITIVE(b->typeinfo)
173                                         || (TYPEINFO_RETURNADDRESS(a->typeinfo)
174                                                 != TYPEINFO_RETURNADDRESS(b->typeinfo)))
175                                 {
176                                         a->type = TYPE_VOID;
177                                         changed = true;
178                                 }
179                         }
180                         else {
181                                 /* 'a' is a reference */
182                                 if (TYPEINFO_IS_PRIMITIVE(b->typeinfo)) {
183                                         a->type = TYPE_VOID;
184                                         changed = true;
185                                 }
186                                 else {
187                                         /* two reference types are merged. There cannot be */
188                                         /* a merge error. In the worst case we get j.l.O.  */
189                                         r = typeinfo_merge(m,&(a->typeinfo),&(b->typeinfo));
190                                         if (r == typecheck_FAIL)
191                                                 return r;
192                                         changed |= r;
193                                 }
194                         }
195                 }
196                 a++;
197                 b++;
198         }
199         return changed;
200 }
201
202 static typecheck_result typecheck_stackbased_merge(verifier_state *state,
203                                                                                                    basicblock *destblock,
204                                                                                                    typedescriptor_t *stack,
205                                                                                                    s4 stackdepth)
206 {
207         s4 i;
208         s4 destidx;
209         typedescriptor_t *stackfloor;
210         typedescriptor_t *sp;
211         typedescriptor_t *dp;
212         typecheck_result r;
213         bool changed = false;
214
215         destidx = destblock->nr;
216
217         if (stackdepth != state->indepth[destidx]) {
218                 exceptions_throw_verifyerror(state->m, "Stack depth mismatch");
219                 return typecheck_FAIL;
220         }
221
222         stackfloor = stack - (stackdepth - 1);
223
224         sp = stackfloor;
225         dp = state->startstack + (destidx * state->m->maxstack);
226
227         for (i=0; i<stackdepth; ++i, ++sp, ++dp) {
228                 if (sp->type != dp->type) {
229                         exceptions_throw_verifyerror(state->m, "Mismatched stack types");
230                         return typecheck_FAIL;
231                 }
232                 if (dp->type == TYPE_ADR) {
233                         if (TYPEINFO_IS_PRIMITIVE(dp->typeinfo)) {
234                                 /* dp has returnAddress type */
235                                 if (TYPEINFO_IS_PRIMITIVE(sp->typeinfo)) {
236                                         if (TYPEINFO_RETURNADDRESS(dp->typeinfo) != TYPEINFO_RETURNADDRESS(sp->typeinfo)) {
237                                                 exceptions_throw_verifyerror(state->m, "Mismatched stack types");
238                                                 return typecheck_FAIL;
239                                         }
240                                 }
241                                 else {
242                                         exceptions_throw_verifyerror(state->m,"Merging returnAddress with reference");
243                                         return typecheck_FAIL;
244                                 }
245                         }
246                         else {
247                                 /* dp has reference type */
248                                 if (TYPEINFO_IS_PRIMITIVE(sp->typeinfo)) {
249                                         exceptions_throw_verifyerror(state->m,"Merging reference with returnAddress");
250                                         return typecheck_FAIL;
251                                 }
252                                 r = typeinfo_merge(state->m,&(dp->typeinfo),&(sp->typeinfo));
253                                 if (r == typecheck_FAIL)
254                                         return r;
255                                 changed |= r;
256                         }
257                 }
258         }
259
260         dp = state->startlocals + (destidx * state->numlocals);
261         r = typecheck_stackbased_merge_locals(state->m, dp, state->locals, state->numlocals);
262         if (r == typecheck_FAIL)
263                 return r;
264         changed |= r;
265
266         return changed;
267 }
268
269 static bool typecheck_stackbased_reach(verifier_state *state,
270                                                                            basicblock *destblock,
271                                                                            typedescriptor_t *stack,
272                                                                            s4 stackdepth)
273 {
274         bool changed = false;
275         typecheck_result r;
276
277         assert(destblock);
278
279         if (destblock->flags == BBTYPECHECK_UNDEF) {
280                 /* The destblock has never been reached before */
281
282                 TYPECHECK_COUNT(stat_copied);
283                 LOG1("block L%03d reached first time",destblock->nr); LOGSTR("\t");
284                 DOLOG( typecheck_stackbased_show_state(state, stack, stack - (stackdepth - 1), false); );
285
286                 state->indepth[destblock->nr] = stackdepth;
287
288                 MCOPY(state->startstack + (destblock->nr * state->m->maxstack),
289                           stack - (stackdepth - 1),
290                           typedescriptor_t,
291                           stackdepth);
292
293                 MCOPY(state->startlocals + (destblock->nr * state->numlocals),
294                           state->locals,
295                           typedescriptor_t,
296                           state->numlocals);
297
298                 changed = true;
299         }
300         else {
301                 /* The destblock has already been reached before */
302
303                 TYPECHECK_COUNT(stat_merged);
304                 LOG1("block L%03d reached before", destblock->nr); LOGSTR("\t");
305                 DOLOG( typecheck_stackbased_show_state(state, stack, stack - (stackdepth - 1), false); );
306
307                 r = typecheck_stackbased_merge(state, destblock, stack, stackdepth);
308                 if (r == typecheck_FAIL)
309                         return false;
310                 changed = r;
311
312                 TYPECHECK_COUNTIF(changed,stat_merging_changed);
313         }
314
315         if (changed) {
316                 LOG("\tchanged!");
317                 destblock->flags = BBTYPECHECK_REACHED;
318                 /* XXX is this check ok? */
319                 if (destblock->nr <= state->bptr->nr) {
320                         LOG("\tREPEAT!");
321                         state->repeat = true;
322                 }
323         }
324         return true;
325 }
326
327
328 /* typecheck_stackbased_verify_fieldaccess *************************************
329
330    Verify an ICMD_{GET,PUT}{STATIC,FIELD}
331
332    IN:
333        state............the current state of the verifier
334            instance.........the instance slot, or NULL
335            value............the value slot, or NULL
336            stack............stack after popping the arguments
337
338    RETURN VALUE:
339        stack pointer....successful verification,
340            NULL.............an exception has been thrown.
341
342 *******************************************************************************/
343
344 static typedescriptor_t *typecheck_stackbased_verify_fieldaccess(
345                 verifier_state *state,
346                 typedescriptor_t *instance,
347                 typedescriptor_t *value,
348                 typedescriptor_t *stack)
349 {
350         jitdata *jd;
351
352         jd = state->jd;
353
354 #define TYPECHECK_STACKBASED
355 #define EXCEPTION  do { return NULL; } while (0)
356 #define STATE  state
357 #include <typecheck-fields.inc>
358 #undef  EXCEPTION
359 #undef  STATE
360 #undef  TYPECHECK_STACKBASED
361
362         return stack;
363
364 throw_stack_overflow:
365         LOG("STACK OVERFLOW!");
366         exceptions_throw_verifyerror(state->m, "Stack size too large");
367         return NULL;
368 }
369
370 static bool typecheck_stackbased_verify_invocation(verifier_state *state,
371                                                                                                    typedescriptor_t *stack,
372                                                                                                    typedescriptor_t *stackfloor)
373 {
374         s4 paramslots;
375         methoddesc *md;
376         typedescriptor_t *dv;
377
378         /* check stack depth */
379
380         /* XXX parse params */
381
382         INSTRUCTION_GET_METHODDESC(state->iptr, md);
383
384         paramslots = md->paramslots;
385
386         if ((stack - stackfloor) + 1 < paramslots) {
387                 exceptions_throw_verifyerror(state->m, 
388                                 "Trying to pop operand of an empty stack");
389                 return false;
390         }
391
392         dv = stack - (paramslots - 1);
393
394 #define TYPECHECK_STACKBASED
395 #define OP1   dv
396 #include <typecheck-invoke.inc>
397 #undef  OP1
398 #undef  TYPECHECK_STACKBASED
399
400         return true;
401 }
402
403 static bool typecheck_stackbased_verify_builtin(verifier_state *state,
404                                                                                                 typedescriptor_t *stack,
405                                                                                                 typedescriptor_t *stackfloor)
406 {
407         s4 paramslots;
408         typedescriptor_t *dv;
409
410         /* check stack depth */
411
412         /* XXX parse params */
413
414         paramslots = state->iptr->sx.s23.s3.bte->md->paramslots;
415
416         if ((stack - stackfloor) + 1 < paramslots) {
417                 exceptions_throw_verifyerror(state->m, 
418                                 "Trying to pop operand of an empty stack");
419                 return false;
420         }
421
422         dv = stack - (paramslots - 1);
423
424 #define TYPECHECK_STACKBASED
425 #define OP1   dv
426 #define TYPECHECK_INT(s)  CHECK_STACK_TYPE(*(s), TYPE_INT)
427 #define TYPECHECK_ADR(s)  CHECK_STACK_TYPE(*(s), TYPE_ADR)
428 #define TYPECHECK_LNG(s)  CHECK_STACK_TYPE(*(s), TYPE_LNG)
429 #define TYPECHECK_FLT(s)  CHECK_STACK_TYPE(*(s), TYPE_FLT)
430 #define TYPECHECK_DBL(s)  CHECK_STACK_TYPE(*(s), TYPE_DBL)
431 #include <typecheck-builtins.inc>
432 #undef  OP1
433 #undef  TYPECHECK_STACKBASED
434
435         return true;
436
437 throw_stack_type_error:
438         exceptions_throw_verifyerror(state->m, "Wrong type on stack"); /* XXX */
439         return false;
440 }
441
442 static bool typecheck_stackbased_multianewarray(verifier_state *state,
443                                                                                                 typedescriptor_t *stack,
444                                                                                                 typedescriptor_t *stackfloor)
445 {
446         /* XXX recombine with verify_multianewarray */
447
448         classinfo *arrayclass;
449         arraydescriptor *desc;
450         s4 i;
451         typedescriptor_t *sp;
452         typedescriptor_t *dst;
453
454         /* destination slot */
455
456         i = state->iptr->s1.argcount;
457
458         dst = stack - (i-1);
459
460         /* check the array lengths on the stack */
461
462         if ((stack - stackfloor) + 1 < i) {
463                 exceptions_throw_verifyerror(state->m, 
464                                 "Trying to pop operand of an empty stack");
465                 return false;
466         }
467
468         if (i < 1)
469                 TYPECHECK_VERIFYERROR_bool("Illegal dimension argument");
470
471         for (sp = dst; sp <= stack; ++sp) {
472                 if (sp->type != TYPE_INT) {
473                         exceptions_throw_verifyerror_for_stack(state->m, TYPE_INT);
474                         return false;
475                 }
476         }
477
478         /* check array descriptor */
479
480         if (INSTRUCTION_IS_RESOLVED(state->iptr)) {
481                 /* the array class reference has already been resolved */
482                 arrayclass = state->iptr->sx.s23.s3.c.cls;
483                 if (!arrayclass)
484                         TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with unlinked class");
485                 if ((desc = arrayclass->vftbl->arraydesc) == NULL)
486                         TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
487                 if (desc->dimension < state->iptr->s1.argcount)
488                         TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
489
490                 /* set the array type of the result */
491                 typeinfo_init_classinfo(&(dst->typeinfo), arrayclass);
492         }
493         else {
494                 const char *p;
495                 constant_classref *cr;
496
497                 /* the array class reference is still unresolved */
498                 /* check that the reference indicates an array class of correct dimension */
499                 cr = state->iptr->sx.s23.s3.c.ref;
500                 i = 0;
501                 p = cr->name->text;
502                 while (p[i] == '[')
503                         i++;
504                 /* { the dimension of the array class == i } */
505                 if (i < 1)
506                         TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
507                 if (i < state->iptr->s1.argcount)
508                         TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
509
510                 /* set the array type of the result */
511                 if (!typeinfo_init_class(&(dst->typeinfo),CLASSREF_OR_CLASSINFO(cr)))
512                         return false;
513         }
514
515         /* everything ok */
516         return true;
517
518 }
519
520 static void typecheck_stackbased_add_jsr_caller(typecheck_jsr_t *jsr,
521                                                                                                 basicblock *bptr)
522 {
523         typecheck_jsr_caller_t *jc;
524
525         for (jc = jsr->callers; jc; jc = jc->next)
526                 if (jc->callblock == bptr)
527                         return;
528
529         jc = DNEW(typecheck_jsr_caller_t);
530         jc->next = jsr->callers;
531         jc->callblock = bptr;
532         jsr->callers = jc;
533 }
534
535 static typedescriptor_t *typecheck_stackbased_jsr(verifier_state *state,
536                                                                                                 typedescriptor_t *stack,
537                                                                                                 typedescriptor_t *stackfloor)
538 {
539         typecheck_jsr_t *jsr;
540         basicblock *tbptr;
541         jitdata *jd;
542         s4 i;
543
544         jd = state->jd;
545
546         tbptr = state->iptr->sx.s23.s3.jsrtarget.block;
547         jsr = state->jsrinfos[tbptr->nr];
548
549         if (jsr && tbptr->flags == BBFINISHED) {
550
551                 LOG1("another JSR to analysed subroutine L%03d", tbptr->nr);
552                 if (jsr->active) {
553                         exceptions_throw_verifyerror(state->m, "Recursive JSR");
554                         return NULL;
555                 }
556
557                 assert(jsr->callers);
558                 assert(jsr->callers->callblock);
559
560                 /* copy the stack of the RET edge */
561
562                 MCOPY(stackfloor, jsr->retstack, typedescriptor_t, jsr->retdepth);
563                 stack = stackfloor + (jsr->retdepth - 1);
564
565                 /* copy variables that were used in the subroutine from the RET edge */
566
567                 for (i=0; i<state->numlocals; ++i)
568                         if (jsr->usedlocals[i])
569                                 state->locals[i] = jsr->retlocals[i];
570
571                 /* reach the following block */
572
573                 if (!typecheck_stackbased_reach(state, state->bptr->next, stack, 
574                                         (stack - stackfloor) + 1))
575                         return NULL;
576         }
577         else {
578                 if (!jsr) {
579                         LOG1("first JSR to block L%03d", tbptr->nr);
580
581                         jsr = DNEW(typecheck_jsr_t);
582                         state->jsrinfos[tbptr->nr] = jsr;
583                         jsr->callers = NULL;
584                         jsr->blockflags = DMNEW(char, state->basicblockcount);
585                         jsr->retblock = NULL;
586                         jsr->start = tbptr;
587                         jsr->usedlocals = DMNEW(char, state->numlocals);
588                         MZERO(jsr->usedlocals, char, state->numlocals);
589                         jsr->retlocals = DMNEW(typedescriptor_t, state->numlocals);
590                         jsr->retstack = DMNEW(typedescriptor_t, state->m->maxstack);
591                         jsr->retdepth = 0;
592                 }
593                 else {
594                         LOG1("re-analysing JSR to block L%03d", tbptr->nr);
595                 }
596
597                 jsr->active = true;
598                 jsr->next = state->topjsr;
599                 state->topjsr = jsr;
600
601                 assert(state->iptr->sx.s23.s3.jsrtarget.block->flags == BBTYPECHECK_REACHED);
602
603                 tbptr->flags = BBFINISHED;
604
605                 for (tbptr = state->basicblocks; tbptr != NULL; tbptr = tbptr->next) {
606                         jsr->blockflags[tbptr->nr] = tbptr->flags;
607
608                         if (tbptr->flags == BBTYPECHECK_REACHED)
609                                 tbptr->flags = BBFINISHED;
610                 }
611
612                 state->iptr->sx.s23.s3.jsrtarget.block->flags = BBTYPECHECK_REACHED;
613         }
614
615         /* register this block as a caller, if not already done */
616
617         typecheck_stackbased_add_jsr_caller(jsr, state->bptr);
618
619         return stack;
620 }
621
622 static bool typecheck_stackbased_ret(verifier_state *state,
623                                                                          typedescriptor_t *stack,
624                                                                          typedescriptor_t *stackfloor)
625 {
626         basicblock *tbptr;
627         typecheck_jsr_caller_t *jsrcaller;
628         typecheck_jsr_t *jsr;
629         s4 i;
630
631         /* get the subroutine we are RETurning from */
632
633         tbptr = TYPEINFO_RETURNADDRESS(state->locals[state->iptr->s1.varindex].typeinfo);
634         if (tbptr == NULL) {
635                 exceptions_throw_verifyerror(state->m, "Illegal RET");
636                 return false;
637         }
638
639         LOG1("RET from subroutine L%03d", tbptr->nr);
640         jsr = state->jsrinfos[tbptr->nr];
641         assert(jsr);
642
643         /* check against recursion */
644
645         if (!jsr->active) {
646                 exceptions_throw_verifyerror(state->m, "RET outside of local subroutine");
647                 return false;
648         }
649
650         /* check against multiple RETs for one subroutine */
651
652         if (jsr->retblock && jsr->retblock != state->bptr) {
653                 exceptions_throw_verifyerror(state->m, "Multiple RETs from local subroutine");
654                 return false;
655         }
656
657         /* store data-flow of the RET edge */
658
659         jsr->retblock = state->bptr;
660         jsr->retdepth = (stack - stackfloor) + 1;
661         MCOPY(jsr->retstack, stackfloor, typedescriptor_t, jsr->retdepth);
662         MCOPY(jsr->retlocals, state->locals, typedescriptor_t, state->numlocals);
663
664         /* invalidate the returnAddress used by this RET */
665         /* XXX should we also invalidate the returnAddresses of JSRs that are skipped by this RET? */
666
667         for (i=0; i<state->numlocals; ++i) {
668                 typedescriptor_t *lc = &(jsr->retlocals[i]);
669                 if (TYPE_IS_RETURNADDRESS(lc->type, lc->typeinfo))
670                         if (TYPEINFO_RETURNADDRESS(lc->typeinfo) == tbptr) {
671                                 LOG1("invalidating returnAddress in local %d", i);
672                                 TYPEINFO_INIT_RETURNADDRESS(lc->typeinfo, NULL);
673                         }
674         }
675
676         /* touch all callers of the subroutine, so they are analysed again */
677
678         for (jsrcaller = jsr->callers; jsrcaller != NULL; jsrcaller = jsrcaller->next) {
679                 tbptr = jsrcaller->callblock;
680                 LOG1("touching caller L%03d from RET", tbptr->nr);
681                 assert(jsr->blockflags[tbptr->nr] >= BBFINISHED);
682                 jsr->blockflags[tbptr->nr] = BBTYPECHECK_REACHED; /* XXX repeat? */
683         }
684
685         return true;
686 }
687
688 bool typecheck_stackbased(jitdata *jd)
689 {
690         register verifier_slot_t *stack;
691         verifier_slot_t *stackfloor;
692         s4 len;
693         methoddesc *md;
694         bool maythrow;
695         bool superblockend;
696         verifier_slot_t temp;
697         branch_target_t *table;
698         lookup_target_t *lookup;
699         s4 i;
700         typecheck_result r;
701         verifier_slot_t *dst;
702         verifier_state state;
703         basicblock *tbptr;
704         exception_entry *ex;
705         typedescriptor_t exstack;
706         s4 skip = 0;
707
708         DOLOG( show_method(jd, SHOW_PARSE); );
709
710         /* initialize verifier state */
711
712         state.jd = jd;
713         state.m = jd->m;
714         state.cd = jd->cd;
715         state.basicblocks = jd->basicblocks;
716         state.basicblockcount = jd->basicblockcount;
717         state.topjsr = NULL;
718 #   define STATE (&state)
719
720         /* check that the basicblock numbers are valid */
721
722 #if !defined(NDEBUG)
723         jit_check_basicblock_numbers(jd);
724 #endif
725
726         /* check if this method is an instance initializer method */
727
728     state.initmethod = (state.m->name == utf_init);
729
730         /* allocate parameter descriptors if necessary */
731
732         if (!state.m->parseddesc->params)
733                 if (!descriptor_params_from_paramtypes(state.m->parseddesc,state.m->flags))
734                         return false;
735
736         /* allocate the stack buffers */
737
738         stackfloor = DMNEW(verifier_slot_t, state.m->maxstack + 1);
739         state.stackceiling = stackfloor + state.m->maxstack;
740         stack = stackfloor - 1;
741         state.indepth = DMNEW(s4, state.basicblockcount);
742         state.startstack = DMNEW(verifier_slot_t, state.m->maxstack * state.basicblockcount);
743
744         /* allocate the local variables buffers */
745
746         state.numlocals = state.m->maxlocals;
747         state.validlocals = state.m->maxlocals;
748     if (state.initmethod)
749                 state.numlocals++; /* extra marker variable */
750
751         state.locals = DMNEW(verifier_slot_t, state.numlocals);
752         state.startlocals = DMNEW(verifier_slot_t, state.numlocals * state.basicblockcount);
753
754     /* allocate the buffer of active exception handlers */
755
756     state.handlers = DMNEW(exception_entry*, state.jd->exceptiontablelength + 1);
757
758     /* initialize instack of exception handlers */
759
760         exstack.type = TYPE_ADR;
761         typeinfo_init_classinfo(&(exstack.typeinfo),
762                                                         class_java_lang_Throwable); /* changed later */
763
764     LOG("Exception handler stacks set.\n");
765
766         /* initialize jsr info buffer */
767
768         state.jsrinfos = DMNEW(typecheck_jsr_t *, state.basicblockcount);
769         MZERO(state.jsrinfos, typecheck_jsr_t *, state.basicblockcount);
770
771         /* initialize stack of first block */
772
773         state.indepth[0] = 0;
774
775         /* initialize locals of first block */
776
777     /* if this is an instance method initialize the "this" ref type */
778
779     if (!(state.m->flags & ACC_STATIC)) {
780                 if (state.validlocals < 1)
781                         VERIFY_ERROR("Not enough local variables for method arguments");
782                 dst = state.startlocals;
783                 dst->type = TYPE_ADR;
784                 if (state.initmethod)
785                         TYPEINFO_INIT_NEWOBJECT(dst->typeinfo, NULL);
786                 else
787                         typeinfo_init_classinfo(&(dst->typeinfo), state.m->clazz);
788
789                 skip = 1;
790     }
791
792     LOG("'this' argument set.\n");
793
794         len = typedescriptors_init_from_methoddesc(state.startlocals + skip,
795                         state.m->parseddesc,
796                         state.validlocals, true, skip, &state.returntype);
797         if (len < 0)
798                 return false;
799
800         /* set remaining locals to void */
801
802         for (i = skip + len; i<state.numlocals; ++i)
803                 state.startlocals[i].type = TYPE_VOID;
804
805         /* initialize block flags */
806
807         typecheck_init_flags(&state, BBUNDEF);
808
809         /* iterate until fixpoint reached */
810
811         do {
812
813                 state.repeat = false;
814
815                 /* iterate over the basic blocks */
816
817                 for (state.bptr = state.basicblocks; state.bptr != NULL; state.bptr = state.bptr->next) {
818
819                         if (state.bptr->flags != BBTYPECHECK_REACHED)
820                                 continue;
821
822                         DOLOG( show_basicblock(jd, state.bptr, SHOW_PARSE); );
823
824                         /* mark this block as analysed */
825
826                         state.bptr->flags = BBFINISHED;
827
828                         /* determine the active exception handlers for this block */
829                         /* XXX could use a faster algorithm with sorted lists or  */
830                         /* something?                                             */
831                         /* XXX reuse code from variables based verifer? */
832                         len = 0;
833                         for (ex = STATE->jd->exceptiontable; ex ; ex = ex->down) {
834                                 if ((ex->start->nr <= STATE->bptr->nr) && (ex->end->nr > STATE->bptr->nr)) {
835                                         LOG1("\tactive handler L%03d", ex->handler->nr);
836                                         STATE->handlers[len++] = ex;
837                                 }
838                         }
839                         STATE->handlers[len] = NULL;
840
841                         /* initialize the locals */
842
843                         MCOPY(state.locals,
844                                   state.startlocals + (state.bptr->nr * state.numlocals),
845                                   verifier_slot_t, state.numlocals);
846
847                         /* initialize the stack */
848
849                         len = state.indepth[state.bptr->nr];
850
851                         MCOPY(stackfloor,
852                                   state.startstack + (state.bptr->nr * state.m->maxstack),
853                                   verifier_slot_t, len);
854
855                         stack = stackfloor + (len - 1);
856
857                         /* iterate over the instructions in this block */
858
859                         state.iptr = state.bptr->iinstr;
860                         len = state.bptr->icount;
861
862                         superblockend = false;
863
864                         for (; len--; state.iptr++) {
865
866                                 maythrow = false;
867
868                                 LOGNL;
869                                 DOLOG( typecheck_stackbased_show_state(&state, stack, stackfloor, true); );
870
871                                 switch (state.iptr->opc) {
872 #define TYPECHECK_STACKBASED 1
873 #define STATE (&state)
874 #define IPTR state.iptr
875 #define BPTR state.bptr
876 #define METHOD state.m
877 #define LOCAL_SLOT(index)  (state.locals + (index))
878 #define EXCEPTION                                                    \
879     do {                                                             \
880         LOG("EXCEPTION THROWN!\n");                                  \
881         return false;                                                \
882     } while (0)
883
884 #include <typecheck-stackbased-gen.inc>
885 #undef  TYPECHECK_STACKBASED
886                                 }
887
888                                 /* reach exception handlers for this instruction */
889
890                                 if (maythrow) {
891                                         TYPECHECK_COUNT(stat_ins_maythrow);
892                                         TYPECHECK_MARK(STATE->stat_maythrow);
893                                         LOG("\treaching exception handlers");
894                                         i = 0;
895                                         while (STATE->handlers[i]) {
896                                                 TYPECHECK_COUNT(stat_handlers_reached);
897                                                 if (STATE->handlers[i]->catchtype.any)
898                                                         exstack.typeinfo.typeclass = STATE->handlers[i]->catchtype;
899                                                 else
900                                                         exstack.typeinfo.typeclass.cls = class_java_lang_Throwable;
901                                                 if (!typecheck_stackbased_reach(
902                                                                 STATE,
903                                                                 STATE->handlers[i]->handler,
904                                                                 &exstack, 1))
905                                                         EXCEPTION;
906                                                 i++;
907                                         }
908                                 }
909                         }
910
911                         /* propagate types to the following block */
912
913                         if (!superblockend) {
914                                 if (!typecheck_stackbased_reach(&state, state.bptr->next,
915                                                                                                 stack, stack - stackfloor + 1))
916                                         EXCEPTION;
917                         }
918                 } /* end loop over blocks */
919
920                 while (!state.repeat && state.topjsr) {
921                         LOG1("done analysing subroutine L%03d", state.topjsr->start->nr);
922
923                         /* propagate down used locals */
924
925                         if (state.topjsr->next) {
926                                 for (i=0; i<state.numlocals; ++i)
927                                         state.topjsr->next->usedlocals[i] |= state.topjsr->usedlocals[i];
928                         }
929
930                         /* restore REACHED flags */
931
932                         for (tbptr = state.basicblocks; tbptr != NULL; tbptr = tbptr->next) {
933                                 assert(tbptr->flags != BBTYPECHECK_REACHED);
934                                 if (state.topjsr->blockflags[tbptr->nr] == BBTYPECHECK_REACHED) {
935                                         tbptr->flags = BBTYPECHECK_REACHED;
936                                         state.repeat = true;
937                                 }
938                         }
939
940                         /* dactivate the subroutine */
941
942                         state.topjsr->active = false;
943                         state.topjsr = state.topjsr->next;
944                 }
945         } while (state.repeat);
946
947         /* reset block flags */
948
949         typecheck_reset_flags(&state);
950
951         LOG("typecheck_stackbased successful");
952
953         return true;
954
955 throw_stack_underflow:
956         LOG("STACK UNDERFLOW!");
957         exceptions_throw_verifyerror(state.m, "Unable to pop operand off an empty stack");
958         return false;
959
960 throw_stack_overflow:
961         LOG("STACK OVERFLOW!");
962         exceptions_throw_verifyerror(state.m, "Stack size too large");
963         return false;
964
965 throw_stack_type_error:
966         LOG("STACK TYPE ERROR!");
967         exceptions_throw_verifyerror(state.m, "Mismatched stack types");
968         return false;
969
970 throw_local_type_error:
971         LOG("LOCAL TYPE ERROR!");
972         exceptions_throw_verifyerror(state.m, "Local variable type mismatch");
973         return false;
974
975 throw_stack_category_error:
976         LOG("STACK CATEGORY ERROR!");
977         exceptions_throw_verifyerror(state.m, "Attempt to split long or double on the stack");
978         return false;
979 }
980
981
982 #if defined(TYPECHECK_VERBOSE)
983 static void typecheck_stackbased_show_state(verifier_state *state,
984                                                                                         typedescriptor_t *stack,
985                                                                                         typedescriptor_t *stackfloor,
986                                                                                         bool showins)
987 {
988         typedescriptor_t *sp;
989         s4 i;
990
991         LOGSTR1("stackdepth %d stack [", (stack - stackfloor) + 1);
992         for (sp=stackfloor; sp <= stack; sp++) {
993                 LOGSTR(" ");
994                 DOLOG( typedescriptor_print(stdout, sp); );
995         }
996         LOGSTR(" ] locals [");
997         for (i=0; i<state->numlocals; ++i) {
998                 LOGSTR(" ");
999                 DOLOG( typedescriptor_print(stdout, state->locals + i); );
1000         }
1001         LOGSTR(" ]");
1002         LOGNL;
1003         if (showins && state->iptr < (state->bptr->iinstr + state->bptr->icount)) {
1004                 LOGSTR("\t");
1005                 DOLOG( show_icmd(state->jd, state->iptr, false, SHOW_PARSE); );
1006                 LOGNL;
1007         }
1008 }
1009 #endif
1010
1011 #endif /* defined(ENABLE_VERIFIER) */
1012
1013
1014 /*
1015  * These are local overrides for various environment variables in Emacs.
1016  * Please do not remove this and leave it at the end of the file, where
1017  * Emacs will automagically detect them.
1018  * ---------------------------------------------------------------------
1019  * Local variables:
1020  * mode: c
1021  * indent-tabs-mode: t
1022  * c-basic-offset: 4
1023  * tab-width: 4
1024  * End:
1025  * vim:noexpandtab:sw=4:ts=4:
1026  */
1027