1 /* src/vm/jit/verify/typecheck-invoke.inc - type checking for invocations
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
34 unresolved_method *um; /* struct describing the called method */
35 constant_FMIref *mref; /* reference to the called method */
36 methoddesc *md; /* descriptor of the called method */
37 utf *mname; /* method name */
38 u1 rtype; /* return type of called method */
39 #if !defined(TYPECHECK_TYPEINFERER)
40 methodinfo *mi; /* resolved method (if any) */
41 utf *mclassname; /* name of the method's class */
42 bool specialmethod; /* true if a <...> method is called */
43 int opcode; /* invocation opcode */
44 bool callinginit; /* true if <init> is called */
46 classref_or_classinfo initclass;
48 #if defined(TYPECHECK_VARIABLESBASED)
49 s4 argindex; /* argument variable index */
50 varinfo *av; /* argument variable */
52 typedescriptor *av; /* argument stack slot */
55 resolve_result_t result;
58 #endif /* !defined(TYPECHECK_TYPEINFERER) */
60 /* get the FMIref and the unresolved_method struct (if any) */
61 /* from the instruction */
63 if (INSTRUCTION_IS_UNRESOLVED(state->iptr)) {
64 /* unresolved method */
65 um = state->iptr->sx.s23.s3.um;
71 mref = state->iptr->sx.s23.s3.fmiref;
74 /* get method descriptor and name */
76 md = mref->parseddesc.md;
79 #if !defined(TYPECHECK_TYPEINFERER)
80 /* get method info (if resolved) and classname */
82 if (IS_FMIREF_RESOLVED(mref)) {
84 mclassname = mi->class->name;
88 mclassname = mref->p.classref->name;
91 /* gather some info about this instruction */
93 opcode = state->iptr->opc;
94 invokestatic = (opcode == ICMD_INVOKESTATIC);
95 invokespecial = (opcode == ICMD_INVOKESPECIAL);
96 specialmethod = (mname->text[0] == '<');
98 /* prevent compiler warnings */
102 /* check whether we are calling <init> */
104 callinginit = (invokespecial && mname == utf_init);
105 if (specialmethod && !callinginit)
106 TYPECHECK_VERIFYERROR_bool("Invalid invocation of special method");
108 /* allocate parameters if necessary */
111 if (!descriptor_params_from_paramtypes(md,
112 (invokestatic) ? ACC_STATIC : ACC_NONE))
115 /* check parameter types */
117 #if defined(TYPECHECK_STACKBASED)
118 av = stack - (md->paramslots - 1);
119 for (i=0; i<md->paramcount; ++i) {
121 i = md->paramcount; /* number of parameters including 'this'*/
123 argindex = state->iptr->sx.s23.s2.args[i];
126 LOG1("\t\tparam %d",i);
127 td = md->paramtypes + i;
129 if (av->type != td->type)
130 TYPECHECK_VERIFYERROR_bool("Parameter type mismatch in method invocation");
132 if (av->type == TYPE_ADR) {
133 LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
134 if (i==0 && callinginit)
136 /* first argument to <init> method */
137 if (!TYPEINFO_IS_NEWOBJECT(av->typeinfo))
138 TYPECHECK_VERIFYERROR_bool("Calling <init> on initialized object");
140 /* get the address of the NEW instruction */
141 LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
142 ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo);
144 initclass = ins[-1].sx.val.c;
146 initclass.cls = state->m->class;
147 LOGSTR("\t\tclass: "); LOGNAME(initclass); LOGNL;
151 /* non-adress argument. if this is the first argument and we are */
152 /* invoking an instance method, this is an error. */
153 if (i==0 && !invokestatic) {
154 TYPECHECK_VERIFYERROR_bool("Parameter type mismatch for 'this' argument");
159 #if defined(TYPECHECK_STACKBASED)
160 av += (IS_2_WORD_TYPE(av->type)) ? 2 : 1;
165 LOG("\treplacing uninitialized object");
166 /* replace uninitialized object type on stack */
168 /* for all live-in and live-through variables */
169 #if defined(TYPECHECK_VARIABLESBASED)
170 for (i=0; i<state->iptr->s1.argcount; ++i) {
171 argindex = state->iptr->sx.s23.s2.args[i];
174 for (av=stackfloor; av <= stack; ++av) {
176 if (av->type == TYPE_ADR
177 && TYPEINFO_IS_NEWOBJECT(av->typeinfo)
178 && TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo) == ins)
180 LOG("\treplacing uninitialized type");
182 #if defined(TYPECHECK_VARIABLESBASED)
183 /* If this stackslot is in the instack of
184 * this basic block we must save the type(s)
185 * we are going to replace.
187 /* XXX this needs a new check */
188 if (state->bptr->invars
189 && argindex >= state->bptr->invars[0]
190 && argindex < state->bptr->varstart
191 && !state->savedinvars)
193 typestate_save_invars(state);
195 #endif /* defined(TYPECHECK_VARIABLESBASED) */
197 if (!typeinfo_init_class(&(av->typeinfo),initclass))
202 /* replace uninitialized object type in locals */
203 #if defined(TYPECHECK_VARIABLESBASED)
204 if (!typevector_init_object(state->jd->var, ins, initclass,
208 /* XXX should reuse typevector code */
209 for (i=0; i<state->numlocals; ++i) {
210 if (state->locals[i].type == TYPE_ADR
211 && TYPEINFO_IS_NEWOBJECT(state->locals[i].typeinfo)
212 && TYPEINFO_NEWOBJECT_INSTRUCTION(state->locals[i].typeinfo) == ins)
214 if (!typeinfo_init_class(&(state->locals[i].typeinfo), initclass))
220 /* initializing the 'this' reference? */
223 TYPECHECK_ASSERT(state->initmethod);
224 /* { we are initializing the 'this' reference } */
225 /* must be <init> of current class or direct superclass */
226 /* the current class is linked, so must be its superclass. thus we can be */
227 /* sure that resolving will be trivial. */
232 if (!resolve_classref(state->m,mref->p.classref,resolveLazy,false,true,&cls))
233 return false; /* exception */
236 /* if lazy resolving did not succeed, it's not one of the allowed classes */
237 /* otherwise we check it directly */
238 if (cls == NULL || (cls != state->m->class && cls != state->m->class->super.cls)) {
239 TYPECHECK_VERIFYERROR_bool("<init> calling <init> of the wrong class");
242 /* set our marker variable to type int */
243 LOG("\tsetting <init> marker");
244 #if defined(TYPECHECK_VARIABLESBASED)
245 typevector_store(jd->var, state->numlocals-1, TYPE_INT, NULL);
247 state->locals[state->numlocals-1].type = TYPE_INT;
251 /* { we are initializing an instance created with NEW } */
252 if ((IS_CLASSREF(initclass) ? initclass.ref->name : initclass.cls->name) != mclassname) {
253 TYPECHECK_VERIFYERROR_bool("wrong <init> called for uninitialized reference");
256 } /* end if (callinginit) */
258 /* try to resolve the method lazily */
260 result = resolve_method_lazy(state->m, mref, invokespecial);
262 /* perform verification checks */
264 if (result == resolveSucceeded) {
266 assert(IS_FMIREF_RESOLVED(mref));
270 result = resolve_method_verifier_checks(state->m,
276 /* check types of parameters */
278 if (result == resolveSucceeded && !invokestatic)
279 result = resolve_method_instance_type_checks(
284 #if defined(TYPECHECK_VARIABLESBASED)
285 if (result == resolveSucceeded)
286 result = resolve_method_param_type_checks(
287 jd, state->m, state->iptr,
290 if (result == resolveSucceeded)
291 result = resolve_method_param_type_checks_stackbased(
292 state->m, mi, invokestatic, stack);
295 /* impose loading constraints */
297 if (result == resolveSucceeded) {
298 /* XXX state->m->class may have to be wrong when inlining */
299 if (!resolve_method_loading_constraints(state->m->class, mi))
303 if (result == resolveFailed)
306 if (result == resolveSucceeded) {
307 /* if this call is monomorphic, turn it into an INVOKESPECIAL */
309 if ((state->iptr->opc == ICMD_INVOKEVIRTUAL)
310 && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
312 state->iptr->opc = ICMD_INVOKESPECIAL;
313 state->iptr->flags.bits |= INS_FLAG_CHECK;
317 /* resolution must be deferred */
320 um = resolve_create_unresolved_method(state->m->class, state->m,
329 /* record subtype constraints for parameters */
331 if (!invokestatic && !resolve_constrain_unresolved_method_instance(
335 return false; /* XXX maybe wrap exception */
337 #if defined(TYPECHECK_VARIABLESBASED)
338 if (!resolve_constrain_unresolved_method_params(
339 jd, um, state->m, state->iptr))
340 return false; /* XXX maybe wrap exception */
342 if (!resolve_constrain_unresolved_method_params_stackbased(
343 um, state->m, stack))
344 return false; /* XXX maybe wrap exception */
347 /* store the unresolved_method pointer */
349 state->iptr->sx.s23.s3.um = um;
350 state->iptr->flags.bits |= INS_FLAG_UNRESOLVED;
352 #endif /* !defined(TYPECHECK_TYPEINFERER) */
354 /* set the return type */
356 rtype = md->returntype.type;
357 if (rtype != TYPE_VOID) {
359 if (!typeinfo_init_from_typedesc(&(md->returntype), NULL, &(dv->typeinfo)))
365 * These are local overrides for various environment variables in Emacs.
366 * Please do not remove this and leave it at the end of the file, where
367 * Emacs will automagically detect them.
368 * ---------------------------------------------------------------------
371 * indent-tabs-mode: t
375 * vim:noexpandtab:sw=4:ts=4:filetype=c: