Line data Source code
1 : /* src/vm/jit/verify/typecheck-typeinferer.c - type inference pass
2 :
3 : Copyright (C) 1996-2013
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 : #include "vm/jit/verify/typecheck-typeinferer.hpp"
26 : #include "config.h"
27 :
28 : #include <assert.h>
29 : #include <string.h>
30 :
31 : #include "mm/memory.hpp"
32 : #include "mm/dumpmemory.hpp"
33 :
34 : #include "native/native.hpp"
35 :
36 : #include "toolbox/logging.hpp"
37 :
38 : #include "vm/access.hpp"
39 : #include "vm/array.hpp"
40 : #include "vm/descriptor.hpp" // for typedesc, methoddesc, etc
41 : #include "vm/exceptions.hpp"
42 : #include "vm/global.hpp"
43 : #include "vm/globals.hpp"
44 : #include "vm/options.hpp"
45 : #include "vm/primitive.hpp"
46 : #include "vm/resolve.hpp"
47 : #include "vm/types.hpp"
48 : #include "vm/vm.hpp"
49 :
50 : #include "vm/jit/builtin.hpp"
51 : #include "vm/jit/jit.hpp"
52 : #include "vm/jit/show.hpp"
53 : #include "vm/jit/parse.hpp"
54 :
55 : #include "vm/jit/ir/instruction.hpp"
56 :
57 : #define TYPECHECK_NO_STATISTICS
58 : #include "vm/jit/verify/typecheck-common.hpp"
59 :
60 :
61 : /* macros used by the generated code ******************************************/
62 :
63 : #define EXCEPTION do { return false; } while (0)
64 : #define VERIFY_ERROR(msg) assert(false)
65 :
66 : #define CHECK_LOCAL_TYPE(index, t) \
67 : assert(jd->var[(index)].type == (t));
68 :
69 : #define STORE_LOCAL(t, index) \
70 : do { \
71 : typevector_store(jd->var, (index), (t), NULL); \
72 : } while (0)
73 :
74 : #define STORE_LOCAL_2_WORD(t, index) \
75 : do { \
76 : typevector_store(jd->var, (index), (t), NULL); \
77 : } while (0)
78 :
79 : #define REACH_BLOCK(target) \
80 : do { \
81 : if (!typestate_reach(state, (target), \
82 : state->bptr->outvars, jd->var, \
83 : state->bptr->outdepth)) \
84 : return false; \
85 : } while (0)
86 :
87 : #define REACH(target) REACH_BLOCK((target).block)
88 :
89 : #define TYPECHECK_INT(v) assert(jd->var[(v)].type == TYPE_INT)
90 : #define TYPECHECK_ADR(v) assert(jd->var[(v)].type == TYPE_ADR)
91 :
92 :
93 : /* handle_fieldaccess **********************************************************
94 :
95 : Verify an ICMD_{GET,PUT}{STATIC,FIELD}(CONST)?
96 :
97 : IN:
98 : state............the current state of the verifier
99 :
100 : RETURN VALUE:
101 : true.............successful verification,
102 : false............an exception has been thrown.
103 :
104 : *******************************************************************************/
105 :
106 : static bool
107 0 : handle_fieldaccess(verifier_state *state,
108 : varinfo *instance,
109 : varinfo *value)
110 : {
111 : jitdata *jd;
112 :
113 0 : jd = state->jd;
114 :
115 : #define TYPECHECK_TYPEINFERER
116 : #include <typecheck-fields.inc>
117 : #undef TYPECHECK_TYPEINFERER
118 :
119 0 : return true;
120 : }
121 :
122 :
123 : /* handle_invocation ***********************************************************
124 :
125 : Verify an ICMD_INVOKE* instruction.
126 :
127 : IN:
128 : state............the current state of the verifier
129 :
130 : RETURN VALUE:
131 : true.............successful verification,
132 : false............an exception has been thrown.
133 :
134 : *******************************************************************************/
135 :
136 : static bool
137 0 : handle_invocation(verifier_state *state)
138 : {
139 : jitdata *jd;
140 : varinfo *dv; /* output variable of current instruction */
141 :
142 0 : jd = state->jd;
143 0 : dv = VAROP(state->iptr->dst);
144 :
145 : #define TYPECHECK_TYPEINFERER
146 : #define OP1 VAR(state->iptr->sx.s23.s2.args[0])
147 : #include <typecheck-invoke.inc>
148 : #undef OP1
149 : #undef TYPECHECK_TYPEINFERER
150 :
151 0 : return true;
152 : }
153 :
154 :
155 : /* handle_builtin **************************************************************
156 :
157 : Verify the call of a builtin method.
158 :
159 : IN:
160 : state............the current state of the verifier
161 :
162 : RETURN VALUE:
163 : true.............successful verification,
164 : false............an exception has been thrown.
165 :
166 : *******************************************************************************/
167 :
168 : static bool
169 0 : handle_builtin(verifier_state *state)
170 : {
171 : jitdata *jd;
172 : varinfo *dv; /* output variable of current instruction */
173 :
174 0 : jd = state->jd;
175 0 : dv = VAROP(state->iptr->dst);
176 :
177 : #define TYPECHECK_TYPEINFERER
178 : #define OP1 state->iptr->sx.s23.s2.args[0]
179 : #include <typecheck-builtins.inc>
180 : #undef OP1
181 : #undef TYPECHECK_TYPEINFERER
182 :
183 0 : return true;
184 : }
185 :
186 : /* handle_multianewarray *******************************************************
187 :
188 : Verify a MULTIANEWARRAY instruction.
189 :
190 : IN:
191 : state............the current state of the verifier
192 :
193 : RETURN VALUE:
194 : true.............successful verification,
195 : false............an exception has been thrown.
196 :
197 : *******************************************************************************/
198 :
199 : static bool
200 0 : handle_multianewarray(verifier_state *state)
201 : {
202 : jitdata *jd;
203 : varinfo *dv; /* output variable of current instruction */
204 :
205 0 : jd = state->jd;
206 0 : dv = VAROP(state->iptr->dst);
207 :
208 : #define TYPECHECK_TYPEINFERER
209 : #include <typecheck-multianewarray.inc>
210 : #undef TYPECHECK_TYPEINFERER
211 :
212 0 : return true;
213 : }
214 :
215 :
216 : /* handle_basic_block **********************************************************
217 :
218 : Perform bytecode verification of a basic block.
219 :
220 : IN:
221 : state............the current state of the verifier
222 :
223 : RETURN VALUE:
224 : true.............successful verification,
225 : false............an exception has been thrown.
226 :
227 : *******************************************************************************/
228 :
229 : static bool
230 0 : handle_basic_block(verifier_state *state)
231 : {
232 : int opcode; /* current opcode */
233 : int len; /* for counting instructions, etc. */
234 : bool superblockend; /* true if no fallthrough to next block */
235 : instruction *iptr; /* the current instruction */
236 : basicblock *tbptr; /* temporary for target block */
237 : bool maythrow; /* true if this instruction may throw */
238 : s4 i;
239 : branch_target_t *table;
240 : lookup_target_t *lookup;
241 0 : jitdata *jd = state->jd;
242 : exception_entry *ex;
243 :
244 : OLD_LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",state->bptr->nr);
245 : OLD_LOGFLUSH;
246 : DOLOG(show_basicblock(jd, state->bptr, SHOW_STACK));
247 :
248 0 : superblockend = false;
249 0 : state->bptr->state = basicblock::FINISHED;
250 :
251 : /* prevent compiler warnings */
252 :
253 :
254 : /* determine the active exception handlers for this block */
255 : /* XXX could use a faster algorithm with sorted lists or */
256 : /* something? */
257 0 : len = 0;
258 0 : for (ex = state->jd->exceptiontable; ex ; ex = ex->down) {
259 0 : if ((ex->start->nr <= state->bptr->nr) && (ex->end->nr > state->bptr->nr)) {
260 : OLD_LOG1("active handler L%03d", ex->handler->nr);
261 0 : state->handlers[len++] = ex;
262 : }
263 : }
264 0 : state->handlers[len] = NULL;
265 :
266 : /* init variable types at the start of this block */
267 0 : typevector_copy_inplace(state->bptr->inlocals, jd->var, state->numlocals);
268 :
269 : DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->invars,
270 : state->bptr->indepth));
271 : DOLOG(typevector_print(stdout, jd->var, state->numlocals));
272 : OLD_LOGNL; OLD_LOGFLUSH;
273 :
274 : /* loop over the instructions */
275 0 : len = state->bptr->icount;
276 0 : state->iptr = state->bptr->iinstr;
277 0 : while (--len >= 0) {
278 : TYPECHECK_COUNT(stat_ins);
279 :
280 0 : iptr = state->iptr;
281 :
282 : DOLOG(typevector_print(stdout, jd->var, state->numlocals));
283 : OLD_LOGNL; OLD_LOGFLUSH;
284 : DOLOG(show_icmd(jd, state->iptr, false, SHOW_STACK)); OLD_LOGNL; OLD_LOGFLUSH;
285 :
286 0 : opcode = iptr->opc;
287 0 : maythrow = false;
288 :
289 0 : switch (opcode) {
290 :
291 : /* include generated code for ICMDs verification */
292 :
293 : #define TYPECHECK_TYPEINFERER
294 : #define STATE state
295 : #define METHOD (state->m)
296 : #define IPTR iptr
297 : #define BPTR (state->bptr)
298 : #include <typecheck-typeinferer-gen.inc>
299 : #undef STATE
300 : #undef METHOD
301 : #undef IPTR
302 : #undef BPTR
303 : #undef TYPECHECK_TYPEINFERER
304 :
305 : default:
306 0 : vm_abort("missing ICMD in type inferer: %d\n", opcode);
307 : }
308 :
309 : /* reach exception handlers for this instruction */
310 :
311 0 : if (maythrow) {
312 : TYPECHECK_COUNT(stat_ins_maythrow);
313 : TYPECHECK_MARK(state->stat_maythrow);
314 : OLD_LOG("reaching exception handlers");
315 0 : i = 0;
316 0 : while (state->handlers[i]) {
317 : TYPECHECK_COUNT(stat_handlers_reached);
318 0 : if (state->handlers[i]->catchtype.any)
319 0 : VAR(state->exinvars)->typeinfo.typeclass = state->handlers[i]->catchtype;
320 : else
321 0 : VAR(state->exinvars)->typeinfo.typeclass.cls = class_java_lang_Throwable;
322 0 : if (!typestate_reach(state,
323 0 : state->handlers[i]->handler,
324 : &(state->exinvars), jd->var, 1))
325 0 : return false;
326 0 : i++;
327 : }
328 : }
329 :
330 : OLD_LOG("\t\tnext instruction");
331 0 : state->iptr++;
332 : } /* while instructions */
333 :
334 : OLD_LOG("instructions done");
335 : OLD_LOGSTR("RESULT=> ");
336 : DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->outvars,
337 : state->bptr->outdepth));
338 : DOLOG(typevector_print(stdout, jd->var, state->numlocals));
339 : OLD_LOGNL; OLD_LOGFLUSH;
340 :
341 : /* propagate stack and variables to the following block */
342 0 : if (!superblockend) {
343 : OLD_LOG("reaching following block");
344 0 : tbptr = state->bptr->next;
345 0 : while (tbptr->state == basicblock::DELETED) {
346 0 : tbptr = tbptr->next;
347 : }
348 0 : if (!typestate_reach(state,tbptr,state->bptr->outvars, jd->var,
349 : state->bptr->outdepth))
350 0 : return false;
351 : }
352 :
353 0 : return true;
354 : }
355 :
356 :
357 0 : bool typecheck_infer_types(jitdata *jd)
358 : {
359 : methodinfo *meth;
360 : codegendata *cd;
361 : varinfo *savedlocals;
362 : verifier_state state; /* current state of the verifier */
363 :
364 : /* get required compiler data */
365 :
366 0 : meth = jd->m;
367 0 : cd = jd->cd;
368 :
369 : /* some logging on entry */
370 :
371 :
372 : OLD_LOGSTR("\n==============================================================================\n");
373 : DOLOG( show_method(jd, SHOW_STACK) );
374 : OLD_LOGSTR("\n==============================================================================\n");
375 : OLD_LOGMETHOD("Entering type inference: ",cd->method);
376 :
377 : /* initialize the verifier state */
378 :
379 0 : state.m = meth;
380 0 : state.jd = jd;
381 0 : state.cd = cd;
382 0 : state.basicblockcount = jd->basicblockcount;
383 0 : state.basicblocks = jd->basicblocks;
384 0 : state.savedindices = NULL;
385 0 : state.savedinvars = NULL;
386 :
387 : /* check that the basicblock numbers are valid */
388 :
389 : #if !defined(NDEBUG)
390 0 : jit_check_basicblock_numbers(jd);
391 : #endif
392 :
393 : /* check if this method is an instance initializer method */
394 :
395 0 : state.initmethod = (state.m->name == utf8::init);
396 :
397 : /* initialize the basic block flags for the following CFG traversal */
398 :
399 0 : typecheck_init_state(&state, basicblock::FINISHED);
400 :
401 : /* number of local variables */
402 :
403 : /* In <init> methods we use an extra local variable to indicate whether */
404 : /* the 'this' reference has been initialized. */
405 : /* TYPE_VOID...means 'this' has not been initialized, */
406 : /* TYPE_INT....means 'this' has been initialized. */
407 :
408 0 : state.numlocals = state.jd->localcount;
409 0 : state.validlocals = state.numlocals;
410 0 : if (state.initmethod)
411 0 : state.numlocals++; /* VERIFIER_EXTRA_LOCALS */
412 :
413 : /* allocate the buffer of active exception handlers */
414 :
415 0 : state.handlers = (exception_entry**) DumpMemory::allocate(sizeof(exception_entry*) * (state.jd->exceptiontablelength + 1));
416 :
417 : /* save local variables */
418 :
419 0 : savedlocals = (varinfo*) DumpMemory::allocate(sizeof(varinfo) * state.numlocals);
420 0 : MCOPY(savedlocals, jd->var, varinfo, state.numlocals);
421 :
422 : /* initialized local variables of first block */
423 :
424 0 : if (!typecheck_init_locals(&state, false))
425 0 : return false;
426 :
427 : /* initialize invars of exception handlers */
428 :
429 0 : state.exinvars = state.numlocals;
430 0 : VAR(state.exinvars)->type = TYPE_ADR;
431 0 : VAR(state.exinvars)->typeinfo.init_class(class_java_lang_Throwable); /* changed later */
432 :
433 : OLD_LOG("Exception handler stacks set.\n");
434 :
435 : // loop while there are still blocks to be checked
436 0 : do {
437 : TYPECHECK_COUNT(count_iterations);
438 :
439 0 : state.repeat = false;
440 0 : state.bptr = state.basicblocks;
441 :
442 0 : for (; state.bptr; state.bptr = state.bptr->next) {
443 : OLD_LOGSTR1("---- BLOCK %04d, ", state.bptr->nr);
444 : OLD_LOGSTR1("blockflags: %d\n", state.bptr->state);
445 : OLD_LOGFLUSH;
446 :
447 : // verify reached block
448 0 : if (state.bptr->state == basicblock::TYPECHECK_REACHED) {
449 0 : if (!handle_basic_block(&state))
450 0 : return false;
451 : }
452 : } // for blocks
453 :
454 : OLD_LOGIF(state.repeat,"state.repeat == true");
455 : } while (state.repeat);
456 :
457 : /* statistics */
458 : /* reset the flags of blocks we haven't reached */
459 :
460 0 : typecheck_reset_state(&state);
461 :
462 : /* restore locals */
463 :
464 0 : MCOPY(jd->var, savedlocals, varinfo, state.numlocals);
465 :
466 : /* everything's ok */
467 :
468 : OLD_LOGimp("exiting type inference");
469 0 : return true;
470 : }
471 :
472 :
473 : /*
474 : * These are local overrides for various environment variables in Emacs.
475 : * Please do not remove this and leave it at the end of the file, where
476 : * Emacs will automagically detect them.
477 : * ---------------------------------------------------------------------
478 : * Local variables:
479 : * mode: c++
480 : * indent-tabs-mode: t
481 : * c-basic-offset: 4
482 : * tab-width: 4
483 : * End:
484 : * vim:noexpandtab:sw=4:ts=4:
485 : */
|