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