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