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 */
103 descriptor_params_from_paramtypes(
105 (invokestatic) ? ACC_STATIC : ACC_NONE);
107 /* check parameter types */
109 #if defined(TYPECHECK_STACKBASED)
110 av = stack - (md->paramslots - 1);
111 for (i=0; i<md->paramcount; ++i) {
113 i = md->paramcount; /* number of parameters including 'this'*/
115 argindex = state->iptr->sx.s23.s2.args[i];
118 LOG1("\t\tparam %d",i);
119 td = md->paramtypes + i;
121 if (av->type != td->type)
122 TYPECHECK_VERIFYERROR_bool("Parameter type mismatch in method invocation");
124 if (av->type == TYPE_ADR) {
125 LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
126 if (i==0 && callinginit)
128 /* first argument to <init> method */
129 if (!TYPEINFO_IS_NEWOBJECT(av->typeinfo))
130 TYPECHECK_VERIFYERROR_bool("Calling <init> on initialized object");
132 /* get the address of the NEW instruction */
133 LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
134 ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo);
136 initclass = ins[-1].sx.val.c;
138 initclass.cls = state->m->clazz;
139 LOGSTR("\t\tclass: "); LOGNAME(initclass); LOGNL;
143 /* non-adress argument. if this is the first argument and we are */
144 /* invoking an instance method, this is an error. */
145 if (i==0 && !invokestatic) {
146 TYPECHECK_VERIFYERROR_bool("Parameter type mismatch for 'this' argument");
151 #if defined(TYPECHECK_STACKBASED)
152 av += (IS_2_WORD_TYPE(av->type)) ? 2 : 1;
157 LOG("\treplacing uninitialized object");
158 /* replace uninitialized object type on stack */
160 /* for all live-in and live-through variables */
161 #if defined(TYPECHECK_VARIABLESBASED)
162 for (i=0; i<state->iptr->s1.argcount; ++i) {
163 argindex = state->iptr->sx.s23.s2.args[i];
166 for (av=stackfloor; av <= stack; ++av) {
168 if (av->type == TYPE_ADR
169 && TYPEINFO_IS_NEWOBJECT(av->typeinfo)
170 && TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo) == ins)
172 LOG("\treplacing uninitialized type");
174 #if defined(TYPECHECK_VARIABLESBASED)
175 /* If this stackslot is in the instack of
176 * this basic block we must save the type(s)
177 * we are going to replace.
179 /* XXX this needs a new check */
180 if (state->bptr->invars
181 && argindex >= state->bptr->invars[0]
182 && argindex < state->bptr->varstart
183 && !state->savedinvars)
185 typestate_save_invars(state);
187 #endif /* defined(TYPECHECK_VARIABLESBASED) */
189 if (!typeinfo_init_class(&(av->typeinfo),initclass))
194 /* replace uninitialized object type in locals */
195 #if defined(TYPECHECK_VARIABLESBASED)
196 if (!typevector_init_object(state->jd->var, ins, initclass,
200 /* XXX should reuse typevector code */
201 for (i=0; i<state->numlocals; ++i) {
202 if (state->locals[i].type == TYPE_ADR
203 && TYPEINFO_IS_NEWOBJECT(state->locals[i].typeinfo)
204 && TYPEINFO_NEWOBJECT_INSTRUCTION(state->locals[i].typeinfo) == ins)
206 if (!typeinfo_init_class(&(state->locals[i].typeinfo), initclass))
212 /* initializing the 'this' reference? */
215 TYPECHECK_ASSERT(state->initmethod);
216 /* { we are initializing the 'this' reference } */
217 /* must be <init> of current class or direct superclass */
218 /* the current class is linked, so must be its superclass. thus we can be */
219 /* sure that resolving will be trivial. */
224 if (!resolve_classref(state->m,mref->p.classref,resolveLazy,false,true,&cls))
225 return false; /* exception */
228 /* if lazy resolving did not succeed, it's not one of the allowed classes */
229 /* otherwise we check it directly */
230 if (cls == NULL || (cls != state->m->clazz && cls != state->m->clazz->super)) {
231 TYPECHECK_VERIFYERROR_bool("<init> calling <init> of the wrong class");
234 /* set our marker variable to type int */
235 LOG("\tsetting <init> marker");
236 #if defined(TYPECHECK_VARIABLESBASED)
237 typevector_store(jd->var, state->numlocals-1, TYPE_INT, NULL);
239 state->locals[state->numlocals-1].type = TYPE_INT;
243 /* { we are initializing an instance created with NEW } */
244 if ((IS_CLASSREF(initclass) ? initclass.ref->name : initclass.cls->name) != mclassname) {
245 TYPECHECK_VERIFYERROR_bool("wrong <init> called for uninitialized reference");
248 } /* end if (callinginit) */
250 /* try to resolve the method lazily */
252 result = resolve_method_lazy(state->m, mref, invokespecial);
254 /* perform verification checks */
256 if (result == resolveSucceeded) {
258 assert(IS_FMIREF_RESOLVED(mref));
262 result = resolve_method_verifier_checks(state->m,
268 /* check types of parameters */
270 if (result == resolveSucceeded && !invokestatic)
271 result = resolve_method_instance_type_checks(
276 #if defined(TYPECHECK_VARIABLESBASED)
277 if (result == resolveSucceeded)
278 result = resolve_method_param_type_checks(
279 jd, state->m, state->iptr,
282 if (result == resolveSucceeded)
283 result = resolve_method_param_type_checks_stackbased(
284 state->m, mi, invokestatic, stack);
287 /* impose loading constraints */
289 if (result == resolveSucceeded) {
290 /* XXX state->m->clazz may have to be wrong when inlining */
291 if (!resolve_method_loading_constraints(state->m->clazz, mi))
295 if (result == resolveFailed)
298 if (result == resolveSucceeded) {
299 /* if this call is monomorphic, turn it into an INVOKESPECIAL */
301 if ((state->iptr->opc == ICMD_INVOKEVIRTUAL)
302 && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
304 state->iptr->opc = ICMD_INVOKESPECIAL;
305 state->iptr->flags.bits |= INS_FLAG_CHECK;
309 /* resolution must be deferred */
312 um = resolve_create_unresolved_method(state->m->clazz, state->m,
321 /* record subtype constraints for parameters */
323 if (!invokestatic && !resolve_constrain_unresolved_method_instance(
327 return false; /* XXX maybe wrap exception */
329 #if defined(TYPECHECK_VARIABLESBASED)
330 if (!resolve_constrain_unresolved_method_params(
331 jd, um, state->m, state->iptr))
332 return false; /* XXX maybe wrap exception */
334 if (!resolve_constrain_unresolved_method_params_stackbased(
335 um, state->m, stack))
336 return false; /* XXX maybe wrap exception */
339 /* store the unresolved_method pointer */
341 state->iptr->sx.s23.s3.um = um;
342 state->iptr->flags.bits |= INS_FLAG_UNRESOLVED;
344 #endif /* !defined(TYPECHECK_TYPEINFERER) */
346 /* set the return type */
348 rtype = md->returntype.type;
349 if (rtype != TYPE_VOID) {
351 if (!typeinfo_init_from_typedesc(&(md->returntype), NULL, &(dv->typeinfo)))
357 * These are local overrides for various environment variables in Emacs.
358 * Please do not remove this and leave it at the end of the file, where
359 * Emacs will automagically detect them.
360 * ---------------------------------------------------------------------
363 * indent-tabs-mode: t
367 * vim:noexpandtab:sw=4:ts=4:filetype=c: