Removed return value from descriptor_params_from_paramtypes.
[cacao.git] / src / vm / jit / verify / typecheck-invoke.inc
1 /* src/vm/jit/verify/typecheck-invoke.inc - type checking for invocations
2
3    Copyright (C) 1996-2011
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
26 {
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 */
38         instruction *ins;
39         classref_or_classinfo initclass;
40         typedesc *td;
41 #if defined(TYPECHECK_VARIABLESBASED)
42         s4 argindex;                            /* argument variable index */
43         varinfo *av;                                  /* argument variable */
44 #else
45         typedescriptor_t *av;                       /* argument stack slot */
46 #endif
47         int i;                                                  /* counter */
48         resolve_result_t result;
49         bool invokestatic;
50         bool invokespecial;
51 #endif /* !defined(TYPECHECK_TYPEINFERER) */
52
53         /* get the FMIref and the unresolved_method struct (if any) */
54         /* from the instruction                                     */
55
56         if (INSTRUCTION_IS_UNRESOLVED(state->iptr)) {
57                 /* unresolved method */
58                 um = state->iptr->sx.s23.s3.um;
59                 mref = um->methodref;
60         }
61         else {
62                 /* resolved method */
63                 um = NULL;
64                 mref = state->iptr->sx.s23.s3.fmiref;
65         }
66
67         /* get method descriptor and name */
68
69         md = mref->parseddesc.md;
70         mname = mref->name;
71
72 #if !defined(TYPECHECK_TYPEINFERER)
73         /* get method info (if resolved) and classname */
74
75         if (IS_FMIREF_RESOLVED(mref)) {
76                 mi = mref->p.method;
77                 mclassname = mi->clazz->name;
78         }
79         else {
80                 mi = NULL;
81                 mclassname = mref->p.classref->name;
82         }
83
84         /* gather some info about this instruction */
85
86         opcode = state->iptr->opc;
87         invokestatic = (opcode == ICMD_INVOKESTATIC);
88         invokespecial = (opcode == ICMD_INVOKESPECIAL);
89         specialmethod = (mname->text[0] == '<');
90
91         /* prevent compiler warnings */
92
93         ins = NULL;
94
95         /* check whether we are calling <init> */
96         
97         callinginit = (invokespecial && mname == utf_init);
98         if (specialmethod && !callinginit)
99                 TYPECHECK_VERIFYERROR_bool("Invalid invocation of special method");
100
101         /* allocate parameters if necessary */
102         
103         if (!md->params)
104                 descriptor_params_from_paramtypes(
105                         md,
106                         (invokestatic) ? ACC_STATIC : ACC_NONE);
107
108         /* check parameter types */
109
110 #if defined(TYPECHECK_STACKBASED)
111         av = stack - (md->paramslots - 1);
112         for (i=0; i<md->paramcount; ++i) {
113 #else
114         i = md->paramcount; /* number of parameters including 'this'*/
115         while (--i >= 0) {
116                 argindex = state->iptr->sx.s23.s2.args[i];
117                 av = VAR(argindex);
118 #endif
119                 LOG1("\t\tparam %d",i);
120                 td = md->paramtypes + i;
121
122                 if (av->type != td->type)
123                         TYPECHECK_VERIFYERROR_bool("Parameter type mismatch in method invocation");
124
125                 if (av->type == TYPE_ADR) {
126                         LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
127                         if (i==0 && callinginit)
128                         {
129                                 /* first argument to <init> method */
130                                 if (!TYPEINFO_IS_NEWOBJECT(av->typeinfo))
131                                         TYPECHECK_VERIFYERROR_bool("Calling <init> on initialized object");
132
133                                 /* get the address of the NEW instruction */
134                                 LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
135                                 ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo);
136                                 if (ins)
137                                         initclass = ins[-1].sx.val.c;
138                                 else
139                                         initclass.cls = state->m->clazz;
140                                 LOGSTR("\t\tclass: "); LOGNAME(initclass); LOGNL;
141                         }
142                 }
143                 else {
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");
148                         }
149                 }
150                 LOG("\t\tok");
151
152 #if defined(TYPECHECK_STACKBASED)
153                 av += (IS_2_WORD_TYPE(av->type)) ? 2 : 1;
154 #endif
155         }
156
157         if (callinginit) {
158                 LOG("\treplacing uninitialized object");
159                 /* replace uninitialized object type on stack */
160
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];
165                         av = VAR(argindex);
166 #else
167                 for (av=stackfloor; av <= stack; ++av) {
168 #endif
169                         if (av->type == TYPE_ADR
170                                         && TYPEINFO_IS_NEWOBJECT(av->typeinfo)
171                                         && TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo) == ins)
172                         {
173                                 LOG("\treplacing uninitialized type");
174
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.
179                                  */
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)
185                                 {
186                                         typestate_save_invars(state);
187                                 }
188 #endif /* defined(TYPECHECK_VARIABLESBASED) */
189
190                                 if (!typeinfo_init_class(&(av->typeinfo),initclass))
191                                         return false;
192                         }
193                 }
194
195                 /* replace uninitialized object type in locals */
196 #if defined(TYPECHECK_VARIABLESBASED)
197                 if (!typevector_init_object(state->jd->var, ins, initclass,
198                                         state->numlocals))
199                         return false;
200 #else
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)
206                         {
207                                 if (!typeinfo_init_class(&(state->locals[i].typeinfo), initclass))
208                                         return false;
209                         }
210                 }
211 #endif
212
213                 /* initializing the 'this' reference? */
214                 if (!ins) {
215                         classinfo *cls;
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.                                   */
221                         if (mi) {
222                                 cls = mi->clazz;
223                         }
224                         else {
225                                 if (!resolve_classref(state->m,mref->p.classref,resolveLazy,false,true,&cls))
226                                         return false; /* exception */
227                         }
228
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");
233                         }
234
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);
239 #else
240                         state->locals[state->numlocals-1].type = TYPE_INT;
241 #endif
242                 }
243                 else {
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");
247                         }
248                 }
249         } /* end if (callinginit) */
250
251         /* try to resolve the method lazily */
252
253         result = resolve_method_lazy(state->m, mref, invokespecial);
254
255         /* perform verification checks */
256
257         if (result == resolveSucceeded) {
258
259                 assert(IS_FMIREF_RESOLVED(mref));
260
261                 mi = mref->p.method;
262
263                 result = resolve_method_verifier_checks(state->m, 
264                                                                                                 mref,
265                                                                                                 mi,
266                                                                                                 invokestatic);
267         }
268
269         /* check types of parameters */
270
271         if (result == resolveSucceeded && !invokestatic)
272                 result = resolve_method_instance_type_checks(
273                                 state->m, mi,
274                                 &(OP1->typeinfo),
275                                 invokespecial);
276
277 #if defined(TYPECHECK_VARIABLESBASED)
278         if (result == resolveSucceeded)
279                 result = resolve_method_param_type_checks(
280                                 jd, state->m, state->iptr,
281                                 mi, invokestatic);
282 #else
283         if (result == resolveSucceeded)
284                 result = resolve_method_param_type_checks_stackbased(
285                                 state->m, mi, invokestatic, stack);
286 #endif
287
288         /* impose loading constraints */
289
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))
293                         return false;
294         }
295
296         if (result == resolveFailed)
297                 return false;
298
299         if (result == resolveSucceeded) {
300                 /* if this call is monomorphic, turn it into an INVOKESPECIAL */
301
302                 if ((state->iptr->opc == ICMD_INVOKEVIRTUAL)
303                         && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
304                 {
305                         state->iptr->opc         = ICMD_INVOKESPECIAL;
306                         state->iptr->flags.bits |= INS_FLAG_CHECK;
307                 }
308         }
309         else {
310                 /* resolution must be deferred */
311
312                 if (!um) {
313                         um = resolve_create_unresolved_method(state->m->clazz, state->m,
314                                         mref, 
315                                         invokestatic,
316                                         invokespecial);
317
318                         if (!um)
319                                 return false;
320                 }
321
322                 /* record subtype constraints for parameters */
323
324                 if (!invokestatic && !resolve_constrain_unresolved_method_instance(
325                                         um, state->m, 
326                                         &(OP1->typeinfo),
327                                         invokespecial))
328                         return false; /* XXX maybe wrap exception */
329
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 */
334 #else
335                 if (!resolve_constrain_unresolved_method_params_stackbased(
336                                         um, state->m, stack))
337                         return false; /* XXX maybe wrap exception */
338 #endif
339
340                 /* store the unresolved_method pointer */
341
342                 state->iptr->sx.s23.s3.um = um;
343                 state->iptr->flags.bits |= INS_FLAG_UNRESOLVED;
344         }
345 #endif /* !defined(TYPECHECK_TYPEINFERER) */
346
347         /* set the return type */
348
349         rtype = md->returntype.type;
350         if (rtype != TYPE_VOID) {
351                 dv->type = rtype;
352                 if (!typeinfo_init_from_typedesc(&(md->returntype), NULL, &(dv->typeinfo)))
353                         return false;
354         }
355 }
356
357 /*
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  * ---------------------------------------------------------------------
362  * Local variables:
363  * mode: c
364  * indent-tabs-mode: t
365  * c-basic-offset: 4
366  * tab-width: 4
367  * End:
368  * vim:noexpandtab:sw=4:ts=4:filetype=c:
369  */