PR163: descriptor_params_from_paramtypes is protected by a mutex now (per descriptor...
[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         descriptor_params_from_paramtypes(
104                 md,
105                 (invokestatic) ? ACC_STATIC : ACC_NONE);
106
107         /* check parameter types */
108
109 #if defined(TYPECHECK_STACKBASED)
110         av = stack - (md->paramslots - 1);
111         for (i=0; i<md->paramcount; ++i) {
112 #else
113         i = md->paramcount; /* number of parameters including 'this'*/
114         while (--i >= 0) {
115                 argindex = state->iptr->sx.s23.s2.args[i];
116                 av = VAR(argindex);
117 #endif
118                 LOG1("\t\tparam %d",i);
119                 td = md->paramtypes + i;
120
121                 if (av->type != td->type)
122                         TYPECHECK_VERIFYERROR_bool("Parameter type mismatch in method invocation");
123
124                 if (av->type == TYPE_ADR) {
125                         LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
126                         if (i==0 && callinginit)
127                         {
128                                 /* first argument to <init> method */
129                                 if (!TYPEINFO_IS_NEWOBJECT(av->typeinfo))
130                                         TYPECHECK_VERIFYERROR_bool("Calling <init> on initialized object");
131
132                                 /* get the address of the NEW instruction */
133                                 LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
134                                 ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo);
135                                 if (ins)
136                                         initclass = ins[-1].sx.val.c;
137                                 else
138                                         initclass.cls = state->m->clazz;
139                                 LOGSTR("\t\tclass: "); LOGNAME(initclass); LOGNL;
140                         }
141                 }
142                 else {
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");
147                         }
148                 }
149                 LOG("\t\tok");
150
151 #if defined(TYPECHECK_STACKBASED)
152                 av += (IS_2_WORD_TYPE(av->type)) ? 2 : 1;
153 #endif
154         }
155
156         if (callinginit) {
157                 LOG("\treplacing uninitialized object");
158                 /* replace uninitialized object type on stack */
159
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];
164                         av = VAR(argindex);
165 #else
166                 for (av=stackfloor; av <= stack; ++av) {
167 #endif
168                         if (av->type == TYPE_ADR
169                                         && TYPEINFO_IS_NEWOBJECT(av->typeinfo)
170                                         && TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo) == ins)
171                         {
172                                 LOG("\treplacing uninitialized type");
173
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.
178                                  */
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)
184                                 {
185                                         typestate_save_invars(state);
186                                 }
187 #endif /* defined(TYPECHECK_VARIABLESBASED) */
188
189                                 if (!typeinfo_init_class(&(av->typeinfo),initclass))
190                                         return false;
191                         }
192                 }
193
194                 /* replace uninitialized object type in locals */
195 #if defined(TYPECHECK_VARIABLESBASED)
196                 if (!typevector_init_object(state->jd->var, ins, initclass,
197                                         state->numlocals))
198                         return false;
199 #else
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)
205                         {
206                                 if (!typeinfo_init_class(&(state->locals[i].typeinfo), initclass))
207                                         return false;
208                         }
209                 }
210 #endif
211
212                 /* initializing the 'this' reference? */
213                 if (!ins) {
214                         classinfo *cls;
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.                                   */
220                         if (mi) {
221                                 cls = mi->clazz;
222                         }
223                         else {
224                                 if (!resolve_classref(state->m,mref->p.classref,resolveLazy,false,true,&cls))
225                                         return false; /* exception */
226                         }
227
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");
232                         }
233
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);
238 #else
239                         state->locals[state->numlocals-1].type = TYPE_INT;
240 #endif
241                 }
242                 else {
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");
246                         }
247                 }
248         } /* end if (callinginit) */
249
250         /* try to resolve the method lazily */
251
252         result = resolve_method_lazy(state->m, mref, invokespecial);
253
254         /* perform verification checks */
255
256         if (result == resolveSucceeded) {
257
258                 assert(IS_FMIREF_RESOLVED(mref));
259
260                 mi = mref->p.method;
261
262                 result = resolve_method_verifier_checks(state->m, 
263                                                                                                 mref,
264                                                                                                 mi,
265                                                                                                 invokestatic);
266         }
267
268         /* check types of parameters */
269
270         if (result == resolveSucceeded && !invokestatic)
271                 result = resolve_method_instance_type_checks(
272                                 state->m, mi,
273                                 &(OP1->typeinfo),
274                                 invokespecial);
275
276 #if defined(TYPECHECK_VARIABLESBASED)
277         if (result == resolveSucceeded)
278                 result = resolve_method_param_type_checks(
279                                 jd, state->m, state->iptr,
280                                 mi, invokestatic);
281 #else
282         if (result == resolveSucceeded)
283                 result = resolve_method_param_type_checks_stackbased(
284                                 state->m, mi, invokestatic, stack);
285 #endif
286
287         /* impose loading constraints */
288
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))
292                         return false;
293         }
294
295         if (result == resolveFailed)
296                 return false;
297
298         if (result == resolveSucceeded) {
299                 /* if this call is monomorphic, turn it into an INVOKESPECIAL */
300
301                 if ((state->iptr->opc == ICMD_INVOKEVIRTUAL)
302                         && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
303                 {
304                         state->iptr->opc         = ICMD_INVOKESPECIAL;
305                         state->iptr->flags.bits |= INS_FLAG_CHECK;
306                 }
307         }
308         else {
309                 /* resolution must be deferred */
310
311                 if (!um) {
312                         um = resolve_create_unresolved_method(state->m->clazz, state->m,
313                                         mref, 
314                                         invokestatic,
315                                         invokespecial);
316
317                         if (!um)
318                                 return false;
319                 }
320
321                 /* record subtype constraints for parameters */
322
323                 if (!invokestatic && !resolve_constrain_unresolved_method_instance(
324                                         um, state->m, 
325                                         &(OP1->typeinfo),
326                                         invokespecial))
327                         return false; /* XXX maybe wrap exception */
328
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 */
333 #else
334                 if (!resolve_constrain_unresolved_method_params_stackbased(
335                                         um, state->m, stack))
336                         return false; /* XXX maybe wrap exception */
337 #endif
338
339                 /* store the unresolved_method pointer */
340
341                 state->iptr->sx.s23.s3.um = um;
342                 state->iptr->flags.bits |= INS_FLAG_UNRESOLVED;
343         }
344 #endif /* !defined(TYPECHECK_TYPEINFERER) */
345
346         /* set the return type */
347
348         rtype = md->returntype.type;
349         if (rtype != TYPE_VOID) {
350                 dv->type = rtype;
351                 if (!typeinfo_init_from_typedesc(&(md->returntype), NULL, &(dv->typeinfo)))
352                         return false;
353         }
354 }
355
356 /*
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  * ---------------------------------------------------------------------
361  * Local variables:
362  * mode: c
363  * indent-tabs-mode: t
364  * c-basic-offset: 4
365  * tab-width: 4
366  * End:
367  * vim:noexpandtab:sw=4:ts=4:filetype=c:
368  */