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
35 unresolved_method *um; /* struct describing the called method */
36 constant_FMIref *mref; /* reference to the called method */
37 methoddesc *md; /* descriptor of the called method */
38 utf *mname; /* method name */
39 u1 rtype; /* return type of called method */
40 #if !defined(TYPECHECK_TYPEINFERER)
41 methodinfo *mi; /* resolved method (if any) */
42 utf *mclassname; /* name of the method's class */
43 bool specialmethod; /* true if a <...> method is called */
44 int opcode; /* invocation opcode */
45 bool callinginit; /* true if <init> is called */
47 classref_or_classinfo initclass;
49 #if defined(TYPECHECK_VARIABLESBASED)
50 s4 argindex; /* argument variable index */
51 varinfo *av; /* argument variable */
53 typedescriptor *av; /* argument stack slot */
56 resolve_result_t result;
59 #endif /* !defined(TYPECHECK_TYPEINFERER) */
61 /* get the FMIref and the unresolved_method struct (if any) */
62 /* from the instruction */
64 if (INSTRUCTION_IS_UNRESOLVED(state->iptr)) {
65 /* unresolved method */
66 um = state->iptr->sx.s23.s3.um;
72 mref = state->iptr->sx.s23.s3.fmiref;
75 /* get method descriptor and name */
77 md = mref->parseddesc.md;
80 #if !defined(TYPECHECK_TYPEINFERER)
81 /* get method info (if resolved) and classname */
83 if (IS_FMIREF_RESOLVED(mref)) {
85 mclassname = mi->class->name;
89 mclassname = mref->p.classref->name;
92 /* gather some info about this instruction */
94 opcode = state->iptr->opc;
95 invokestatic = (opcode == ICMD_INVOKESTATIC);
96 invokespecial = (opcode == ICMD_INVOKESPECIAL);
97 specialmethod = (mname->text[0] == '<');
99 /* prevent compiler warnings */
103 /* check whether we are calling <init> */
105 callinginit = (invokespecial && mname == utf_init);
106 if (specialmethod && !callinginit)
107 TYPECHECK_VERIFYERROR_bool("Invalid invocation of special method");
109 /* allocate parameters if necessary */
112 if (!descriptor_params_from_paramtypes(md,
113 (invokestatic) ? ACC_STATIC : ACC_NONE))
116 /* check parameter types */
118 #if defined(TYPECHECK_STACKBASED)
119 av = stack - (md->paramslots - 1);
120 for (i=0; i<md->paramcount; ++i) {
122 i = md->paramcount; /* number of parameters including 'this'*/
124 argindex = state->iptr->sx.s23.s2.args[i];
127 LOG1("\t\tparam %d",i);
128 td = md->paramtypes + i;
130 if (av->type != td->type)
131 TYPECHECK_VERIFYERROR_bool("Parameter type mismatch in method invocation");
133 if (av->type == TYPE_ADR) {
134 LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
135 if (i==0 && callinginit)
137 /* first argument to <init> method */
138 if (!TYPEINFO_IS_NEWOBJECT(av->typeinfo))
139 TYPECHECK_VERIFYERROR_bool("Calling <init> on initialized object");
141 /* get the address of the NEW instruction */
142 LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
143 ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo);
145 initclass = ins[-1].sx.val.c;
147 initclass.cls = state->m->class;
148 LOGSTR("\t\tclass: "); LOGNAME(initclass); LOGNL;
152 /* non-adress argument. if this is the first argument and we are */
153 /* invoking an instance method, this is an error. */
154 if (i==0 && !invokestatic) {
155 TYPECHECK_VERIFYERROR_bool("Parameter type mismatch for 'this' argument");
160 #if defined(TYPECHECK_STACKBASED)
161 av += (IS_2_WORD_TYPE(av->type)) ? 2 : 1;
166 LOG("\treplacing uninitialized object");
167 /* replace uninitialized object type on stack */
169 /* for all live-in and live-through variables */
170 #if defined(TYPECHECK_VARIABLESBASED)
171 for (i=0; i<state->iptr->s1.argcount; ++i) {
172 argindex = state->iptr->sx.s23.s2.args[i];
175 for (av=stackfloor; av <= stack; ++av) {
177 if (av->type == TYPE_ADR
178 && TYPEINFO_IS_NEWOBJECT(av->typeinfo)
179 && TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo) == ins)
181 LOG("\treplacing uninitialized type");
183 #if defined(TYPECHECK_VARIABLESBASED)
184 /* If this stackslot is in the instack of
185 * this basic block we must save the type(s)
186 * we are going to replace.
188 /* XXX this needs a new check */
189 if (state->bptr->invars
190 && argindex >= state->bptr->invars[0]
191 && argindex < state->bptr->varstart
192 && !state->savedinvars)
194 typestate_save_invars(state);
196 #endif /* defined(TYPECHECK_VARIABLESBASED) */
198 if (!typeinfo_init_class(&(av->typeinfo),initclass))
203 /* replace uninitialized object type in locals */
204 #if defined(TYPECHECK_VARIABLESBASED)
205 if (!typevector_init_object(state->jd->var, ins, initclass,
209 /* XXX should reuse typevector code */
210 for (i=0; i<state->numlocals; ++i) {
211 if (state->locals[i].type == TYPE_ADR
212 && TYPEINFO_IS_NEWOBJECT(state->locals[i].typeinfo)
213 && TYPEINFO_NEWOBJECT_INSTRUCTION(state->locals[i].typeinfo) == ins)
215 if (!typeinfo_init_class(&(state->locals[i].typeinfo), initclass))
221 /* initializing the 'this' reference? */
224 TYPECHECK_ASSERT(state->initmethod);
225 /* { we are initializing the 'this' reference } */
226 /* must be <init> of current class or direct superclass */
227 /* the current class is linked, so must be its superclass. thus we can be */
228 /* sure that resolving will be trivial. */
233 if (!resolve_classref(state->m,mref->p.classref,resolveLazy,false,true,&cls))
234 return false; /* exception */
237 /* if lazy resolving did not succeed, it's not one of the allowed classes */
238 /* otherwise we check it directly */
239 if (cls == NULL || (cls != state->m->class && cls != state->m->class->super.cls)) {
240 TYPECHECK_VERIFYERROR_bool("<init> calling <init> of the wrong class");
243 /* set our marker variable to type int */
244 LOG("\tsetting <init> marker");
245 #if defined(TYPECHECK_VARIABLESBASED)
246 typevector_store(jd->var, state->numlocals-1, TYPE_INT, NULL);
248 state->locals[state->numlocals-1].type = TYPE_INT;
252 /* { we are initializing an instance created with NEW } */
253 if ((IS_CLASSREF(initclass) ? initclass.ref->name : initclass.cls->name) != mclassname) {
254 TYPECHECK_VERIFYERROR_bool("wrong <init> called for uninitialized reference");
257 } /* end if (callinginit) */
259 /* try to resolve the method lazily */
261 result = resolve_method_lazy(state->m, mref, invokespecial);
263 /* perform verification checks */
265 if (result == resolveSucceeded) {
267 assert(IS_FMIREF_RESOLVED(mref));
271 result = resolve_method_verifier_checks(state->m,
277 /* check types of parameters */
279 if (result == resolveSucceeded && !invokestatic)
280 result = resolve_method_instance_type_checks(
285 #if defined(TYPECHECK_VARIABLESBASED)
286 if (result == resolveSucceeded)
287 result = resolve_method_param_type_checks(
288 jd, state->m, state->iptr,
291 if (result == resolveSucceeded)
292 result = resolve_method_param_type_checks_stackbased(
293 state->m, mi, invokestatic, stack);
296 /* impose loading constraints */
298 if (result == resolveSucceeded) {
299 /* XXX state->m->class may have to be wrong when inlining */
300 if (!resolve_method_loading_constraints(state->m->class, mi))
304 if (result == resolveFailed)
307 if (result == resolveSucceeded) {
308 /* if this call is monomorphic, turn it into an INVOKESPECIAL */
310 if ((state->iptr->opc == ICMD_INVOKEVIRTUAL)
311 && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
313 state->iptr->opc = ICMD_INVOKESPECIAL;
314 state->iptr->flags.bits |= INS_FLAG_CHECK;
318 /* resolution must be deferred */
321 um = resolve_create_unresolved_method(state->m->class, state->m,
330 /* record subtype constraints for parameters */
332 if (!invokestatic && !resolve_constrain_unresolved_method_instance(
336 return false; /* XXX maybe wrap exception */
338 #if defined(TYPECHECK_VARIABLESBASED)
339 if (!resolve_constrain_unresolved_method_params(
340 jd, um, state->m, state->iptr))
341 return false; /* XXX maybe wrap exception */
343 if (!resolve_constrain_unresolved_method_params_stackbased(
344 um, state->m, stack))
345 return false; /* XXX maybe wrap exception */
348 /* store the unresolved_method pointer */
350 state->iptr->sx.s23.s3.um = um;
351 state->iptr->flags.bits |= INS_FLAG_UNRESOLVED;
353 #endif /* !defined(TYPECHECK_TYPEINFERER) */
355 /* set the return type */
357 rtype = md->returntype.type;
358 if (rtype != TYPE_VOID) {
360 if (!typeinfo_init_from_typedesc(&(md->returntype), NULL, &(dv->typeinfo)))
366 * These are local overrides for various environment variables in Emacs.
367 * Please do not remove this and leave it at the end of the file, where
368 * Emacs will automagically detect them.
369 * ---------------------------------------------------------------------
372 * indent-tabs-mode: t
376 * vim:noexpandtab:sw=4:ts=4:filetype=c: