* Removed all Id tags.
[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-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
7
8    This file is part of CACAO.
9
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.
14
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.
19
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
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Edwin Steiner
28
29
30 */
31
32
33 {
34         unresolved_method *um;      /* struct describing the called method */
35         constant_FMIref *mref;           /* reference to the called method */
36         methoddesc *md;                 /* descriptor of the called method */
37         utf *mname;                                         /* method name */
38     u1 rtype;                          /* return type of called method */
39 #if !defined(TYPECHECK_TYPEINFERER)
40         methodinfo *mi;                        /* resolved method (if any) */
41         utf *mclassname;                     /* name of the method's class */
42         bool specialmethod;            /* true if a <...> method is called */
43         int opcode;                                   /* invocation opcode */
44         bool callinginit;                      /* true if <init> is called */
45         instruction *ins;
46         classref_or_classinfo initclass;
47         typedesc *td;
48 #if defined(TYPECHECK_VARIABLESBASED)
49         s4 argindex;                            /* argument variable index */
50         varinfo *av;                                  /* argument variable */
51 #else
52         typedescriptor *av;                         /* argument stack slot */
53 #endif
54         int i;                                                  /* counter */
55         resolve_result_t result;
56         bool invokestatic;
57         bool invokespecial;
58 #endif /* !defined(TYPECHECK_TYPEINFERER) */
59
60         /* get the FMIref and the unresolved_method struct (if any) */
61         /* from the instruction                                     */
62
63         if (INSTRUCTION_IS_UNRESOLVED(state->iptr)) {
64                 /* unresolved method */
65                 um = state->iptr->sx.s23.s3.um;
66                 mref = um->methodref;
67         }
68         else {
69                 /* resolved method */
70                 um = NULL;
71                 mref = state->iptr->sx.s23.s3.fmiref;
72         }
73
74         /* get method descriptor and name */
75
76         md = mref->parseddesc.md;
77         mname = mref->name;
78
79 #if !defined(TYPECHECK_TYPEINFERER)
80         /* get method info (if resolved) and classname */
81
82         if (IS_FMIREF_RESOLVED(mref)) {
83                 mi = mref->p.method;
84                 mclassname = mi->class->name;
85         }
86         else {
87                 mi = NULL;
88                 mclassname = mref->p.classref->name;
89         }
90
91         /* gather some info about this instruction */
92
93         opcode = state->iptr->opc;
94         invokestatic = (opcode == ICMD_INVOKESTATIC);
95         invokespecial = (opcode == ICMD_INVOKESPECIAL);
96         specialmethod = (mname->text[0] == '<');
97
98         /* prevent compiler warnings */
99
100         ins = NULL;
101
102         /* check whether we are calling <init> */
103         
104         callinginit = (invokespecial && mname == utf_init);
105         if (specialmethod && !callinginit)
106                 TYPECHECK_VERIFYERROR_bool("Invalid invocation of special method");
107
108         /* allocate parameters if necessary */
109         
110         if (!md->params)
111                 if (!descriptor_params_from_paramtypes(md,
112                                         (invokestatic) ? ACC_STATIC : ACC_NONE))
113                         return false;
114
115         /* check parameter types */
116
117 #if defined(TYPECHECK_STACKBASED)
118         av = stack - (md->paramslots - 1);
119         for (i=0; i<md->paramcount; ++i) {
120 #else
121         i = md->paramcount; /* number of parameters including 'this'*/
122         while (--i >= 0) {
123                 argindex = state->iptr->sx.s23.s2.args[i];
124                 av = VAR(argindex);
125 #endif
126                 LOG1("\t\tparam %d",i);
127                 td = md->paramtypes + i;
128
129                 if (av->type != td->type)
130                         TYPECHECK_VERIFYERROR_bool("Parameter type mismatch in method invocation");
131
132                 if (av->type == TYPE_ADR) {
133                         LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
134                         if (i==0 && callinginit)
135                         {
136                                 /* first argument to <init> method */
137                                 if (!TYPEINFO_IS_NEWOBJECT(av->typeinfo))
138                                         TYPECHECK_VERIFYERROR_bool("Calling <init> on initialized object");
139
140                                 /* get the address of the NEW instruction */
141                                 LOGSTR("\t\t"); LOGINFO(&(av->typeinfo));
142                                 ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo);
143                                 if (ins)
144                                         initclass = ins[-1].sx.val.c;
145                                 else
146                                         initclass.cls = state->m->class;
147                                 LOGSTR("\t\tclass: "); LOGNAME(initclass); LOGNL;
148                         }
149                 }
150                 else {
151                         /* non-adress argument. if this is the first argument and we are */
152                         /* invoking an instance method, this is an error.                */
153                         if (i==0 && !invokestatic) {
154                                 TYPECHECK_VERIFYERROR_bool("Parameter type mismatch for 'this' argument");
155                         }
156                 }
157                 LOG("\t\tok");
158
159 #if defined(TYPECHECK_STACKBASED)
160                 av += (IS_2_WORD_TYPE(av->type)) ? 2 : 1;
161 #endif
162         }
163
164         if (callinginit) {
165                 LOG("\treplacing uninitialized object");
166                 /* replace uninitialized object type on stack */
167
168                 /* for all live-in and live-through variables */ 
169 #if defined(TYPECHECK_VARIABLESBASED)
170                 for (i=0; i<state->iptr->s1.argcount; ++i) {
171                         argindex = state->iptr->sx.s23.s2.args[i];
172                         av = VAR(argindex);
173 #else
174                 for (av=stackfloor; av <= stack; ++av) {
175 #endif
176                         if (av->type == TYPE_ADR
177                                         && TYPEINFO_IS_NEWOBJECT(av->typeinfo)
178                                         && TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo) == ins)
179                         {
180                                 LOG("\treplacing uninitialized type");
181
182 #if defined(TYPECHECK_VARIABLESBASED)
183                                 /* If this stackslot is in the instack of
184                                  * this basic block we must save the type(s)
185                                  * we are going to replace.
186                                  */
187                                 /* XXX this needs a new check */
188                                 if (state->bptr->invars
189                                                 && argindex >= state->bptr->invars[0]
190                                                 && argindex < state->bptr->varstart 
191                                                 && !state->savedinvars)
192                                 {
193                                         typestate_save_invars(state);
194                                 }
195 #endif /* defined(TYPECHECK_VARIABLESBASED) */
196
197                                 if (!typeinfo_init_class(&(av->typeinfo),initclass))
198                                         return false;
199                         }
200                 }
201
202                 /* replace uninitialized object type in locals */
203 #if defined(TYPECHECK_VARIABLESBASED)
204                 if (!typevector_init_object(state->jd->var, ins, initclass,
205                                         state->numlocals))
206                         return false;
207 #else
208                 /* XXX should reuse typevector code */
209                 for (i=0; i<state->numlocals; ++i) {
210                         if (state->locals[i].type == TYPE_ADR
211                                 && TYPEINFO_IS_NEWOBJECT(state->locals[i].typeinfo)
212                                 && TYPEINFO_NEWOBJECT_INSTRUCTION(state->locals[i].typeinfo) == ins)
213                         {
214                                 if (!typeinfo_init_class(&(state->locals[i].typeinfo), initclass))
215                                         return false;
216                         }
217                 }
218 #endif
219
220                 /* initializing the 'this' reference? */
221                 if (!ins) {
222                         classinfo *cls;
223                         TYPECHECK_ASSERT(state->initmethod);
224                         /* { we are initializing the 'this' reference }                           */
225                         /* must be <init> of current class or direct superclass                   */
226                         /* the current class is linked, so must be its superclass. thus we can be */
227                         /* sure that resolving will be trivial.                                   */
228                         if (mi) {
229                                 cls = mi->class;
230                         }
231                         else {
232                                 if (!resolve_classref(state->m,mref->p.classref,resolveLazy,false,true,&cls))
233                                         return false; /* exception */
234                         }
235
236                         /* if lazy resolving did not succeed, it's not one of the allowed classes */
237                         /* otherwise we check it directly                                         */
238                         if (cls == NULL || (cls != state->m->class && cls != state->m->class->super.cls)) {
239                                 TYPECHECK_VERIFYERROR_bool("<init> calling <init> of the wrong class");
240                         }
241
242                         /* set our marker variable to type int */
243                         LOG("\tsetting <init> marker");
244 #if defined(TYPECHECK_VARIABLESBASED)
245                         typevector_store(jd->var, state->numlocals-1, TYPE_INT, NULL);
246 #else
247                         state->locals[state->numlocals-1].type = TYPE_INT;
248 #endif
249                 }
250                 else {
251                         /* { we are initializing an instance created with NEW } */
252                         if ((IS_CLASSREF(initclass) ? initclass.ref->name : initclass.cls->name) != mclassname) {
253                                 TYPECHECK_VERIFYERROR_bool("wrong <init> called for uninitialized reference");
254                         }
255                 }
256         } /* end if (callinginit) */
257
258         /* try to resolve the method lazily */
259
260         result = resolve_method_lazy(state->m, mref, invokespecial);
261
262         /* perform verification checks */
263
264         if (result == resolveSucceeded) {
265
266                 assert(IS_FMIREF_RESOLVED(mref));
267
268                 mi = mref->p.method;
269
270                 result = resolve_method_verifier_checks(state->m, 
271                                                                                                 mref,
272                                                                                                 mi,
273                                                                                                 invokestatic);
274         }
275
276         /* check types of parameters */
277
278         if (result == resolveSucceeded && !invokestatic)
279                 result = resolve_method_instance_type_checks(
280                                 state->m, mi,
281                                 &(OP1->typeinfo),
282                                 invokespecial);
283
284 #if defined(TYPECHECK_VARIABLESBASED)
285         if (result == resolveSucceeded)
286                 result = resolve_method_param_type_checks(
287                                 jd, state->m, state->iptr,
288                                 mi, invokestatic);
289 #else
290         if (result == resolveSucceeded)
291                 result = resolve_method_param_type_checks_stackbased(
292                                 state->m, mi, invokestatic, stack);
293 #endif
294
295         /* impose loading constraints */
296
297         if (result == resolveSucceeded) {
298                 /* XXX state->m->class may have to be wrong when inlining */
299                 if (!resolve_method_loading_constraints(state->m->class, mi))
300                         return false;
301         }
302
303         if (result == resolveFailed)
304                 return false;
305
306         if (result == resolveSucceeded) {
307                 /* if this call is monomorphic, turn it into an INVOKESPECIAL */
308
309                 if ((state->iptr->opc == ICMD_INVOKEVIRTUAL)
310                         && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
311                 {
312                         state->iptr->opc         = ICMD_INVOKESPECIAL;
313                         state->iptr->flags.bits |= INS_FLAG_CHECK;
314                 }
315         }
316         else {
317                 /* resolution must be deferred */
318
319                 if (!um) {
320                         um = resolve_create_unresolved_method(state->m->class, state->m,
321                                         mref, 
322                                         invokestatic,
323                                         invokespecial);
324
325                         if (!um)
326                                 return false;
327                 }
328
329                 /* record subtype constraints for parameters */
330
331                 if (!invokestatic && !resolve_constrain_unresolved_method_instance(
332                                         um, state->m, 
333                                         &(OP1->typeinfo),
334                                         invokespecial))
335                         return false; /* XXX maybe wrap exception */
336
337 #if defined(TYPECHECK_VARIABLESBASED)
338                 if (!resolve_constrain_unresolved_method_params(
339                                         jd, um, state->m, state->iptr))
340                         return false; /* XXX maybe wrap exception */
341 #else
342                 if (!resolve_constrain_unresolved_method_params_stackbased(
343                                         um, state->m, stack))
344                         return false; /* XXX maybe wrap exception */
345 #endif
346
347                 /* store the unresolved_method pointer */
348
349                 state->iptr->sx.s23.s3.um = um;
350                 state->iptr->flags.bits |= INS_FLAG_UNRESOLVED;
351         }
352 #endif /* !defined(TYPECHECK_TYPEINFERER) */
353
354         /* set the return type */
355
356         rtype = md->returntype.type;
357         if (rtype != TYPE_VOID) {
358                 dv->type = rtype;
359                 if (!typeinfo_init_from_typedesc(&(md->returntype), NULL, &(dv->typeinfo)))
360                         return false;
361         }
362 }
363
364 /*
365  * These are local overrides for various environment variables in Emacs.
366  * Please do not remove this and leave it at the end of the file, where
367  * Emacs will automagically detect them.
368  * ---------------------------------------------------------------------
369  * Local variables:
370  * mode: c
371  * indent-tabs-mode: t
372  * c-basic-offset: 4
373  * tab-width: 4
374  * End:
375  * vim:noexpandtab:sw=4:ts=4:filetype=c:
376  */