1 /* src/vm/jit/verify/typecheck-common.c - shared verifier code
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
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.
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.
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
25 Contact: cacao@cacaojvm.org
27 Authors: Edwin Steiner
36 #include "vm/global.h"
40 #include <vm/exceptions.h>
41 #include <vm/jit/show.h>
42 #include <typecheck-common.h>
44 /****************************************************************************/
46 /****************************************************************************/
48 #ifdef TYPECHECK_VERBOSE_OPT
49 bool opt_typecheckverbose = false;
52 #if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
54 void typecheck_print_var(FILE *file, jitdata *jd, s4 index)
58 assert(index >= 0 && index < jd->varcount);
60 typeinfo_print_type(file, var->type, &(var->typeinfo));
63 void typecheck_print_vararray(FILE *file, jitdata *jd, s4 *vars, int len)
67 for (i=0; i<len; ++i) {
70 typecheck_print_var(file, jd, *vars++);
74 #endif /* defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT) */
77 /****************************************************************************/
79 /****************************************************************************/
81 #if defined(TYPECHECK_STATISTICS)
82 int stat_typechecked = 0;
83 int stat_methods_with_handlers = 0;
84 int stat_methods_maythrow = 0;
85 int stat_iterations[STAT_ITERATIONS+1] = { 0 };
89 int stat_merging_changed = 0;
90 int stat_blocks[STAT_BLOCKS+1] = { 0 };
91 int stat_locals[STAT_LOCALS+1] = { 0 };
93 int stat_ins_maythrow = 0;
94 int stat_ins_stack = 0;
95 int stat_ins_field = 0;
96 int stat_ins_field_unresolved = 0;
97 int stat_ins_field_uninitialized = 0;
98 int stat_ins_invoke = 0;
99 int stat_ins_invoke_unresolved = 0;
100 int stat_ins_primload = 0;
101 int stat_ins_aload = 0;
102 int stat_ins_builtin = 0;
103 int stat_ins_builtin_gen = 0;
104 int stat_ins_branch = 0;
105 int stat_ins_switch = 0;
106 int stat_ins_primitive_return = 0;
107 int stat_ins_areturn = 0;
108 int stat_ins_areturn_unresolved = 0;
109 int stat_ins_athrow = 0;
110 int stat_ins_athrow_unresolved = 0;
111 int stat_ins_unchecked = 0;
112 int stat_handlers_reached = 0;
113 int stat_savedstack = 0;
115 static void print_freq(FILE *file,int *array,int limit)
118 for (i=0; i<limit; ++i)
119 fprintf(file," %3d: %8d\n",i,array[i]);
120 fprintf(file," >=%3d: %8d\n",limit,array[limit]);
123 void typecheck_print_statistics(FILE *file) {
124 fprintf(file,"typechecked methods: %8d\n",stat_typechecked);
125 fprintf(file," with handler(s): %8d\n",stat_methods_with_handlers);
126 fprintf(file," with throw(s) : %8d\n",stat_methods_maythrow);
127 fprintf(file,"reached blocks : %8d\n",stat_reached);
128 fprintf(file,"copied states : %8d\n",stat_copied);
129 fprintf(file,"merged states : %8d\n",stat_merged);
130 fprintf(file,"merging changed : %8d\n",stat_merging_changed);
131 fprintf(file,"handlers reached : %8d\n",stat_handlers_reached);
132 fprintf(file,"saved stack (times): %8d\n",stat_savedstack);
133 fprintf(file,"instructions : %8d\n",stat_ins);
134 fprintf(file," stack : %8d\n",stat_ins_stack);
135 fprintf(file," field access : %8d\n",stat_ins_field);
136 fprintf(file," (unresolved) : %8d\n",stat_ins_field_unresolved);
137 fprintf(file," (uninit.) : %8d\n",stat_ins_field_uninitialized);
138 fprintf(file," invocations : %8d\n",stat_ins_invoke);
139 fprintf(file," (unresolved) : %8d\n",stat_ins_invoke_unresolved);
140 fprintf(file," load primitive : (currently not counted) %8d\n",stat_ins_primload);
141 fprintf(file," load address : %8d\n",stat_ins_aload);
142 fprintf(file," builtins : %8d\n",stat_ins_builtin);
143 fprintf(file," generic : %8d\n",stat_ins_builtin_gen);
144 fprintf(file," branches : %8d\n",stat_ins_branch);
145 fprintf(file," switches : %8d\n",stat_ins_switch);
146 fprintf(file," prim. return : %8d\n",stat_ins_primitive_return);
147 fprintf(file," areturn : %8d\n",stat_ins_areturn);
148 fprintf(file," (unresolved) : %8d\n",stat_ins_areturn_unresolved);
149 fprintf(file," athrow : %8d\n",stat_ins_athrow);
150 fprintf(file," (unresolved) : %8d\n",stat_ins_athrow_unresolved);
151 fprintf(file," unchecked : %8d\n",stat_ins_unchecked);
152 fprintf(file," maythrow : %8d\n",stat_ins_maythrow);
153 fprintf(file,"iterations used:\n");
154 print_freq(file,stat_iterations,STAT_ITERATIONS);
155 fprintf(file,"basic blocks per method / 10:\n");
156 print_freq(file,stat_blocks,STAT_BLOCKS);
157 fprintf(file,"locals:\n");
158 print_freq(file,stat_locals,STAT_LOCALS);
160 #endif /* defined(TYPECHECK_STATISTICS) */
163 /* typecheck_init_flags ********************************************************
165 Initialize the basic block flags for the following CFG traversal.
168 state............the current state of the verifier
169 minflags.........minimum flags value of blocks that should be
172 *******************************************************************************/
174 void typecheck_init_flags(verifier_state *state, s4 minflags)
178 /* set all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
180 for (block = state->basicblocks; block; block = block->next) {
182 #ifdef TYPECHECK_DEBUG
183 /* check for invalid flags */
184 if (block->flags != BBFINISHED && block->flags != BBDELETED && block->flags != BBUNDEF)
186 LOGSTR1("block flags: %d\n",block->flags); LOGFLUSH;
187 TYPECHECK_ASSERT(false);
191 if (block->flags >= minflags) {
192 block->flags = BBTYPECHECK_UNDEF;
196 /* the first block is always reached */
198 if (state->basicblockcount && state->basicblocks[0].flags == BBTYPECHECK_UNDEF)
199 state->basicblocks[0].flags = BBTYPECHECK_REACHED;
203 /* typecheck_reset_flags *******************************************************
205 Reset the flags of basic blocks we have not reached.
208 state............the current state of the verifier
210 *******************************************************************************/
212 void typecheck_reset_flags(verifier_state *state)
216 /* check for invalid flags at exit */
218 #ifdef TYPECHECK_DEBUG
219 for (block = state->basicblocks; block; block = block->next) {
220 if (block->flags != BBDELETED
221 && block->flags != BBUNDEF
222 && block->flags != BBFINISHED
223 && block->flags != BBTYPECHECK_UNDEF) /* typecheck may never reach
224 * some exception handlers,
227 LOG2("block L%03d has invalid flags after typecheck: %d",
228 block->nr,block->flags);
229 TYPECHECK_ASSERT(false);
234 /* Delete blocks we never reached */
236 for (block = state->basicblocks; block; block = block->next) {
237 if (block->flags == BBTYPECHECK_UNDEF)
238 block->flags = BBDELETED;
243 /****************************************************************************/
244 /* TYPESTACK MACROS AND FUNCTIONS */
246 /* These macros and functions act on the 'type stack', which is a shorthand */
247 /* for the types of the stackslots of the current stack. The type of a */
248 /* stack slot is usually described by a TYPE_* constant and -- for TYPE_ADR */
249 /* -- by the typeinfo of the slot. The only thing that makes the type stack */
250 /* more complicated are returnAddresses of local subroutines, because a */
251 /* single stack slot may contain a set of more than one possible return */
252 /* address. This is handled by 'return address sets'. A return address set */
253 /* is kept as a linked list dangling off the typeinfo of the stack slot. */
254 /****************************************************************************/
256 /* typecheck_copy_types ********************************************************
258 Copy the types of the source variables to the destination variables.
261 state............current verifier state
262 srcvars..........array of variable indices to copy
263 dstvars..........array of the destination variables
264 n................number of variables to copy
267 true.............success
268 false............an exception has been thrown
270 *******************************************************************************/
272 bool typecheck_copy_types(verifier_state *state, s4 *srcvars, s4 *dstvars, s4 n)
277 jitdata *jd = state->jd;
279 for (i=0; i < n; ++i, ++srcvars, ++dstvars) {
284 if (dv->type == TYPE_ADR) {
285 TYPEINFO_CLONE(sv->typeinfo,dv->typeinfo);
292 /* typecheck_merge_types *******************************************************
294 Merge the types of the source variables into the destination variables.
297 state............current state of the verifier
298 srcvars..........source variable indices
299 dstvars..........destination variable indices
300 n................number of variables
303 typecheck_TRUE...the destination variables have been modified
304 typecheck_FALSE..the destination variables are unchanged
305 typecheck_FAIL...an exception has been thrown
307 *******************************************************************************/
309 typecheck_result typecheck_merge_types(verifier_state *state,
317 jitdata *jd = state->jd;
319 bool changed = false;
321 for (i=0; i < n; ++i, ++srcvars, ++dstvars) {
325 if (dv->type != sv->type) {
326 exceptions_throw_verifyerror(state->m,"Stack type mismatch");
327 return typecheck_FAIL;
329 if (dv->type == TYPE_ADR) {
330 if (TYPEINFO_IS_PRIMITIVE(dv->typeinfo)) {
331 /* dv has returnAddress type */
332 if (!TYPEINFO_IS_PRIMITIVE(sv->typeinfo)) {
333 exceptions_throw_verifyerror(state->m,"Merging returnAddress with reference");
334 return typecheck_FAIL;
338 /* dv has reference type */
339 if (TYPEINFO_IS_PRIMITIVE(sv->typeinfo)) {
340 exceptions_throw_verifyerror(state->m,"Merging reference with returnAddress");
341 return typecheck_FAIL;
343 r = typeinfo_merge(state->m,&(dv->typeinfo),&(sv->typeinfo));
344 if (r == typecheck_FAIL)
354 /* typestate_merge *************************************************************
356 Merge the types of one state into the destination state.
359 state............current state of the verifier
360 dstvars..........indices of the destinations invars
361 dstlocals........the destinations inlocals
362 srcvars..........indices of the source's outvars
363 srclocals........the source locals
364 n................number of invars (== number of outvars)
367 typecheck_TRUE...destination state has been modified
368 typecheck_FALSE..destination state has not been modified
369 typecheck_FAIL...an exception has been thrown
371 *******************************************************************************/
373 typecheck_result typestate_merge(verifier_state *state,
374 s4 *srcvars, varinfo *srclocals,
375 s4 *dstvars, varinfo *dstlocals,
378 bool changed = false;
381 /* The stack is always merged. If there are returnAddresses on
382 * the stack they are ignored in this step. */
384 r = typecheck_merge_types(state, srcvars, dstvars, n);
385 if (r == typecheck_FAIL)
389 /* merge the locals */
391 r = typevector_merge(state->m, dstlocals, srclocals, state->numlocals);
392 if (r == typecheck_FAIL)
398 /* typestate_reach *************************************************************
400 Reach a destination block and propagate stack and local variable types
403 state............current state of the verifier
404 destblock........destination basic block
405 srcvars..........variable indices of the outvars to propagate
406 srclocals........local variables to propagate
407 n................number of srcvars
410 state->repeat....set to true if the verifier must iterate again
411 over the basic blocks
414 true.............success
415 false............an exception has been thrown
417 *******************************************************************************/
419 bool typestate_reach(verifier_state *state,
420 basicblock *destblock,
421 s4 *srcvars, varinfo *srclocals, s4 n)
424 bool changed = false;
427 LOG1("reaching block L%03d",destblock->nr);
428 TYPECHECK_COUNT(stat_reached);
430 destloc = destblock->inlocals;
432 if (destblock->flags == BBTYPECHECK_UNDEF) {
433 /* The destblock has never been reached before */
435 TYPECHECK_COUNT(stat_copied);
436 LOG1("block L%03d reached first time",destblock->nr);
438 if (!typecheck_copy_types(state, srcvars, destblock->invars, n))
440 typevector_copy_inplace(srclocals, destloc, state->numlocals);
444 /* The destblock has already been reached before */
446 TYPECHECK_COUNT(stat_merged);
447 LOG1("block L%03d reached before", destblock->nr);
449 r = typestate_merge(state, srcvars, srclocals,
450 destblock->invars, destblock->inlocals, n);
451 if (r == typecheck_FAIL)
454 TYPECHECK_COUNTIF(changed,stat_merging_changed);
459 destblock->flags = BBTYPECHECK_REACHED;
460 if (destblock->nr <= state->bptr->nr) {
462 state->repeat = true;
469 /* typecheck_init_locals *******************************************************
471 Initialize the local variables in the verifier state.
474 state............the current state of the verifier
475 newthis..........if true, mark the instance in <init> methods as
476 uninitialized object.
479 true.............success,
480 false............an exception has been thrown.
482 *******************************************************************************/
484 bool typecheck_init_locals(verifier_state *state, bool newthis)
490 jitdata *jd = state->jd;
493 locals = state->basicblocks[0].inlocals;
495 /* allocate parameter descriptors if necessary */
497 if (!state->m->parseddesc->params)
498 if (!descriptor_params_from_paramtypes(state->m->parseddesc,state->m->flags))
501 /* pre-initialize variables as TYPE_VOID */
503 i = state->numlocals;
510 /* if this is an instance method initialize the "this" ref type */
512 if (!(state->m->flags & ACC_STATIC)) {
513 varindex = jd->local_map[5*0 + TYPE_ADR];
514 if (varindex != UNUSED) {
515 if (state->validlocals < 1)
516 TYPECHECK_VERIFYERROR_bool("Not enough local variables for method arguments");
517 v = locals + varindex;
519 if (state->initmethod && newthis)
520 TYPEINFO_INIT_NEWOBJECT(v->typeinfo, NULL);
522 typeinfo_init_classinfo(&(v->typeinfo), state->m->class);
528 LOG("'this' argument set.\n");
530 /* the rest of the arguments and the return type */
532 if (!typeinfo_init_varinfos_from_methoddesc(locals, state->m->parseddesc,
534 skip, /* skip 'this' pointer */
539 LOG("Arguments set.\n");
545 * These are local overrides for various environment variables in Emacs.
546 * Please do not remove this and leave it at the end of the file, where
547 * Emacs will automagically detect them.
548 * ---------------------------------------------------------------------
551 * indent-tabs-mode: t
555 * vim:noexpandtab:sw=4:ts=4: