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