1 /* src/vm/jit/verify/typecheck-invoke.inc - type checking for invocations
3 Copyright (C) 1996-2011
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
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.
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.
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
27 unresolved_method *um; /* struct describing the called method */
28 constant_FMIref *mref; /* reference to the called method */
29 methoddesc *md; /* descriptor of the called method */
30 utf *mname; /* method name */
31 u1 rtype; /* return type of called method */
32 #if !defined(TYPECHECK_TYPEINFERER)
33 methodinfo *mi; /* resolved method (if any) */
34 utf *mclassname; /* name of the method's class */
35 bool specialmethod; /* true if a <...> method is called */
36 int opcode; /* invocation opcode */
37 bool callinginit; /* true if <init> is called */
39 classref_or_classinfo initclass;
41 #if defined(TYPECHECK_VARIABLESBASED)
42 s4 argindex; /* argument variable index */
43 varinfo *av; /* argument variable */
45 typedescriptor_t *av; /* argument stack slot */
48 resolve_result_t result;
51 #endif /* !defined(TYPECHECK_TYPEINFERER) */
53 /* get the FMIref and the unresolved_method struct (if any) */
54 /* from the instruction */
56 if (INSTRUCTION_IS_UNRESOLVED(state->iptr)) {
57 /* unresolved method */
58 um = state->iptr->sx.s23.s3.um;
64 mref = state->iptr->sx.s23.s3.fmiref;
67 /* get method descriptor and name */
69 md = mref->parseddesc.md;
72 #if !defined(TYPECHECK_TYPEINFERER)
73 /* get method info (if resolved) and classname */
75 if (IS_FMIREF_RESOLVED(mref)) {
77 mclassname = mi->clazz->name;
81 mclassname = mref->p.classref->name;
84 /* gather some info about this instruction */
86 opcode = state->iptr->opc;
87 invokestatic = (opcode == ICMD_INVOKESTATIC);
88 invokespecial = (opcode == ICMD_INVOKESPECIAL);
89 specialmethod = (mname->text[0] == '<');
91 /* prevent compiler warnings */
95 /* check whether we are calling <init> */
97 callinginit = (invokespecial && mname == utf_init);
98 if (specialmethod && !callinginit)
99 TYPECHECK_VERIFYERROR_bool("Invalid invocation of special method");
101 /* allocate parameters if necessary */
104 descriptor_params_from_paramtypes(
106 (invokestatic) ? ACC_STATIC : ACC_NONE);
108 /* check parameter types */
110 #if defined(TYPECHECK_STACKBASED)
111 av = stack - (md->paramslots - 1);
112 for (i=0; i<md->paramcount; ++i) {
114 i = md->paramcount; /* number of parameters including 'this'*/
116 argindex = state->iptr->sx.s23.s2.args[i];
119 LOG1("\t\tparam %d",i);
120 td = md->paramtypes + i;
122 if (av->type != td->type)
123 TYPECHECK_VERIFYERROR_bool("Parameter type mismatch in method invocation");
125 if (av->type == TYPE_ADR) {
126 LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
127 if (i==0 && callinginit)
129 /* first argument to <init> method */
130 if (!TYPEINFO_IS_NEWOBJECT(av->typeinfo))
131 TYPECHECK_VERIFYERROR_bool("Calling <init> on initialized object");
133 /* get the address of the NEW instruction */
134 LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
135 ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo);
137 initclass = ins[-1].sx.val.c;
139 initclass.cls = state->m->clazz;
140 LOGSTR("\t\tclass: "); LOGNAME(initclass); LOGNL;
144 /* non-adress argument. if this is the first argument and we are */
145 /* invoking an instance method, this is an error. */
146 if (i==0 && !invokestatic) {
147 TYPECHECK_VERIFYERROR_bool("Parameter type mismatch for 'this' argument");
152 #if defined(TYPECHECK_STACKBASED)
153 av += (IS_2_WORD_TYPE(av->type)) ? 2 : 1;
158 LOG("\treplacing uninitialized object");
159 /* replace uninitialized object type on stack */
161 /* for all live-in and live-through variables */
162 #if defined(TYPECHECK_VARIABLESBASED)
163 for (i=0; i<state->iptr->s1.argcount; ++i) {
164 argindex = state->iptr->sx.s23.s2.args[i];
167 for (av=stackfloor; av <= stack; ++av) {
169 if (av->type == TYPE_ADR
170 && TYPEINFO_IS_NEWOBJECT(av->typeinfo)
171 && TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo) == ins)
173 LOG("\treplacing uninitialized type");
175 #if defined(TYPECHECK_VARIABLESBASED)
176 /* If this stackslot is in the instack of
177 * this basic block we must save the type(s)
178 * we are going to replace.
180 /* XXX this needs a new check */
181 if (state->bptr->invars
182 && argindex >= state->bptr->invars[0]
183 && argindex < state->bptr->varstart
184 && !state->savedinvars)
186 typestate_save_invars(state);
188 #endif /* defined(TYPECHECK_VARIABLESBASED) */
190 if (!typeinfo_init_class(&(av->typeinfo),initclass))
195 /* replace uninitialized object type in locals */
196 #if defined(TYPECHECK_VARIABLESBASED)
197 if (!typevector_init_object(state->jd->var, ins, initclass,
201 /* XXX should reuse typevector code */
202 for (i=0; i<state->numlocals; ++i) {
203 if (state->locals[i].type == TYPE_ADR
204 && TYPEINFO_IS_NEWOBJECT(state->locals[i].typeinfo)
205 && TYPEINFO_NEWOBJECT_INSTRUCTION(state->locals[i].typeinfo) == ins)
207 if (!typeinfo_init_class(&(state->locals[i].typeinfo), initclass))
213 /* initializing the 'this' reference? */
216 TYPECHECK_ASSERT(state->initmethod);
217 /* { we are initializing the 'this' reference } */
218 /* must be <init> of current class or direct superclass */
219 /* the current class is linked, so must be its superclass. thus we can be */
220 /* sure that resolving will be trivial. */
225 if (!resolve_classref(state->m,mref->p.classref,resolveLazy,false,true,&cls))
226 return false; /* exception */
229 /* if lazy resolving did not succeed, it's not one of the allowed classes */
230 /* otherwise we check it directly */
231 if (cls == NULL || (cls != state->m->clazz && cls != state->m->clazz->super)) {
232 TYPECHECK_VERIFYERROR_bool("<init> calling <init> of the wrong class");
235 /* set our marker variable to type int */
236 LOG("\tsetting <init> marker");
237 #if defined(TYPECHECK_VARIABLESBASED)
238 typevector_store(jd->var, state->numlocals-1, TYPE_INT, NULL);
240 state->locals[state->numlocals-1].type = TYPE_INT;
244 /* { we are initializing an instance created with NEW } */
245 if ((IS_CLASSREF(initclass) ? initclass.ref->name : initclass.cls->name) != mclassname) {
246 TYPECHECK_VERIFYERROR_bool("wrong <init> called for uninitialized reference");
249 } /* end if (callinginit) */
251 /* try to resolve the method lazily */
253 result = resolve_method_lazy(state->m, mref, invokespecial);
255 /* perform verification checks */
257 if (result == resolveSucceeded) {
259 assert(IS_FMIREF_RESOLVED(mref));
263 result = resolve_method_verifier_checks(state->m,
269 /* check types of parameters */
271 if (result == resolveSucceeded && !invokestatic)
272 result = resolve_method_instance_type_checks(
277 #if defined(TYPECHECK_VARIABLESBASED)
278 if (result == resolveSucceeded)
279 result = resolve_method_param_type_checks(
280 jd, state->m, state->iptr,
283 if (result == resolveSucceeded)
284 result = resolve_method_param_type_checks_stackbased(
285 state->m, mi, invokestatic, stack);
288 /* impose loading constraints */
290 if (result == resolveSucceeded) {
291 /* XXX state->m->clazz may have to be wrong when inlining */
292 if (!resolve_method_loading_constraints(state->m->clazz, mi))
296 if (result == resolveFailed)
299 if (result == resolveSucceeded) {
300 /* if this call is monomorphic, turn it into an INVOKESPECIAL */
302 if ((state->iptr->opc == ICMD_INVOKEVIRTUAL)
303 && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
305 state->iptr->opc = ICMD_INVOKESPECIAL;
306 state->iptr->flags.bits |= INS_FLAG_CHECK;
310 /* resolution must be deferred */
313 um = resolve_create_unresolved_method(state->m->clazz, state->m,
322 /* record subtype constraints for parameters */
324 if (!invokestatic && !resolve_constrain_unresolved_method_instance(
328 return false; /* XXX maybe wrap exception */
330 #if defined(TYPECHECK_VARIABLESBASED)
331 if (!resolve_constrain_unresolved_method_params(
332 jd, um, state->m, state->iptr))
333 return false; /* XXX maybe wrap exception */
335 if (!resolve_constrain_unresolved_method_params_stackbased(
336 um, state->m, stack))
337 return false; /* XXX maybe wrap exception */
340 /* store the unresolved_method pointer */
342 state->iptr->sx.s23.s3.um = um;
343 state->iptr->flags.bits |= INS_FLAG_UNRESOLVED;
345 #endif /* !defined(TYPECHECK_TYPEINFERER) */
347 /* set the return type */
349 rtype = md->returntype.type;
350 if (rtype != TYPE_VOID) {
352 if (!typeinfo_init_from_typedesc(&(md->returntype), NULL, &(dv->typeinfo)))
358 * These are local overrides for various environment variables in Emacs.
359 * Please do not remove this and leave it at the end of the file, where
360 * Emacs will automagically detect them.
361 * ---------------------------------------------------------------------
364 * indent-tabs-mode: t
368 * vim:noexpandtab:sw=4:ts=4:filetype=c: