* src/vm/jit/verify/typecheck.c (verify_invocation): Moved body to a
[cacao.git] / src / vm / jit / verify / typecheck-invoke.inc
1 {
2         unresolved_method *um;      /* struct describing the called method */
3         constant_FMIref *mref;           /* reference to the called method */
4         methodinfo *mi;                        /* resolved method (if any) */
5         methoddesc *md;                 /* descriptor of the called method */
6         utf *mname;                                         /* method name */
7         utf *mclassname;                     /* name of the method's class */
8         bool specialmethod;            /* true if a <...> method is called */
9         int opcode;                                   /* invocation opcode */
10         bool callinginit;                      /* true if <init> is called */
11         instruction *ins;
12         classref_or_classinfo initclass;
13         typedesc *td;
14         s4 argindex;                            /* argument variable index */
15         varinfo *av;                                  /* argument variable */
16         varinfo *dv;                  /* result variable of the invocation */
17         int i;                                                  /* counter */
18     u1 rtype;                          /* return type of called method */
19         resolve_result_t result;
20         jitdata *jd;
21         bool invokestatic;
22         bool invokespecial;
23
24         jd = state->jd;
25
26         /* get the FMIref and the unresolved_method struct (if any) */
27         /* from the instruction                                     */
28
29         if (INSTRUCTION_IS_UNRESOLVED(state->iptr)) {
30                 /* unresolved method */
31                 um = state->iptr->sx.s23.s3.um;
32                 mref = um->methodref;
33         }
34         else {
35                 /* resolved method */
36                 um = NULL;
37                 mref = state->iptr->sx.s23.s3.fmiref;
38         }
39
40         /* get method descriptor and name */
41
42         md = mref->parseddesc.md;
43         mname = mref->name;
44
45         /* get method info (if resolved) and classname */
46
47         if (IS_FMIREF_RESOLVED(mref)) {
48                 mi = mref->p.method;
49                 mclassname = mi->class->name;
50         }
51         else {
52                 mi = NULL;
53                 mclassname = mref->p.classref->name;
54         }
55
56         opcode = state->iptr[0].opc;
57         invokestatic = (opcode == ICMD_INVOKESTATIC);
58         invokespecial = (opcode == ICMD_INVOKESPECIAL);
59         specialmethod = (mname->text[0] == '<');
60         dv = VAROP(state->iptr->dst);
61
62         /* prevent compiler warnings */
63
64         ins = NULL;
65
66         /* check whether we are calling <init> */
67         
68         callinginit = (invokespecial && mname == utf_init);
69         if (specialmethod && !callinginit)
70                 TYPECHECK_VERIFYERROR_bool("Invalid invocation of special method");
71
72         /* allocate parameters if necessary */
73         
74         if (!md->params)
75                 if (!descriptor_params_from_paramtypes(md,
76                                         (opcode == ICMD_INVOKESTATIC) ? ACC_STATIC : ACC_NONE))
77                         return false;
78
79         /* check parameter types */
80
81         i = md->paramcount; /* number of parameters including 'this'*/
82         while (--i >= 0) {
83                 LOG1("param %d",i);
84                 argindex = state->iptr->sx.s23.s2.args[i];
85                 av = VAR(argindex);
86                 td = md->paramtypes + i;
87
88                 if (av->type != td->type)
89                         TYPECHECK_VERIFYERROR_bool("Parameter type mismatch in method invocation");
90
91                 if (av->type == TYPE_ADR) {
92                         LOGINFO(&(av->typeinfo));
93                         if (i==0 && callinginit)
94                         {
95                                 /* first argument to <init> method */
96                                 if (!TYPEINFO_IS_NEWOBJECT(av->typeinfo))
97                                         TYPECHECK_VERIFYERROR_bool("Calling <init> on initialized object");
98
99                                 /* get the address of the NEW instruction */
100                                 LOGINFO(&(av->typeinfo));
101                                 ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo);
102                                 if (ins)
103                                         initclass = ins[-1].sx.val.c;
104                                 else
105                                         initclass.cls = state->m->class;
106                                 LOGSTR("class: "); LOGNAME(initclass); LOGNL;
107                         }
108                 }
109                 else {
110                         /* non-adress argument. if this is the first argument and we are */
111                         /* invoking an instance method, this is an error.                */
112                         if (i==0 && opcode != ICMD_INVOKESTATIC) {
113                                 TYPECHECK_VERIFYERROR_bool("Parameter type mismatch for 'this' argument");
114                         }
115                 }
116                 LOG("ok");
117         }
118
119         if (callinginit) {
120                 LOG("replacing uninitialized object");
121                 /* replace uninitialized object type on stack */
122
123                 /* for all live-in and live-through variables */ 
124                 for (i=0; i<state->iptr->s1.argcount; ++i) {
125                         argindex = state->iptr->sx.s23.s2.args[i];
126                         av = VAR(argindex);
127                         if (av->type == TYPE_ADR
128                                         && TYPEINFO_IS_NEWOBJECT(av->typeinfo)
129                                         && TYPEINFO_NEWOBJECT_INSTRUCTION(av->typeinfo) == ins)
130                         {
131                                 LOG("replacing uninitialized type");
132
133                                 /* If this stackslot is in the instack of
134                                  * this basic block we must save the type(s)
135                                  * we are going to replace.
136                                  */
137                                 /* XXX this needs a new check */
138                                 if (state->bptr->invars
139                                                 && argindex >= state->bptr->invars[0] 
140                                                 && argindex < state->bptr->varstart 
141                                                 && !state->savedinvars)
142                                 {
143                                         typestate_save_invars(state);
144                                 }
145
146                                 if (!typeinfo_init_class(&(av->typeinfo),initclass))
147                                         return false;
148                         }
149                 }
150
151                 /* replace uninitialized object type in locals */
152                 if (!typevector_init_object(state->jd->var, ins, initclass,
153                                         state->numlocals))
154                         return false;
155
156                 /* initializing the 'this' reference? */
157                 if (!ins) {
158                         classinfo *cls;
159                         TYPECHECK_ASSERT(state->initmethod);
160                         /* { we are initializing the 'this' reference }                           */
161                         /* must be <init> of current class or direct superclass                   */
162                         /* the current class is linked, so must be its superclass. thus we can be */
163                         /* sure that resolving will be trivial.                                   */
164                         if (mi) {
165                                 cls = mi->class;
166                         }
167                         else {
168                                 if (!resolve_classref(state->m,mref->p.classref,resolveLazy,false,true,&cls))
169                                         return false; /* exception */
170                         }
171
172                         /* if lazy resolving did not succeed, it's not one of the allowed classes */
173                         /* otherwise we check it directly                                         */
174                         if (cls == NULL || (cls != state->m->class && cls != state->m->class->super.cls)) {
175                                 TYPECHECK_VERIFYERROR_bool("<init> calling <init> of the wrong class");
176                         }
177
178                         /* set our marker variable to type int */
179                         LOG("setting <init> marker");
180                         typevector_store(jd->var, state->numlocals-1, TYPE_INT, NULL);
181                 }
182                 else {
183                         /* { we are initializing an instance created with NEW } */
184                         if ((IS_CLASSREF(initclass) ? initclass.ref->name : initclass.cls->name) != mclassname) {
185                                 TYPECHECK_VERIFYERROR_bool("wrong <init> called for uninitialized reference");
186                         }
187                 }
188         }
189
190         /* try to resolve the method lazily */
191
192         result = resolve_method_lazy(state->m, mref, invokespecial);
193
194         /* perform verification checks */
195
196         if (result == resolveSucceeded) {
197
198                 assert(IS_FMIREF_RESOLVED(mref));
199
200                 mi = mref->p.method;
201
202                 result = resolve_method_verifier_checks(state->m, 
203                                                                                                 mref,
204                                                                                                 mi,
205                                                                                                 invokestatic);
206         }
207
208         /* check types of parameters */
209
210         if (result == resolveSucceeded && !invokestatic)
211                 result = resolve_method_instance_type_checks(
212                                 state->m, mi, 
213                                 &(VAR(state->iptr->sx.s23.s2.args[0])->typeinfo), 
214                                 invokespecial);
215
216         if (result == resolveSucceeded)
217                 result = resolve_method_param_type_checks(
218                                 jd, state->m, state->iptr,
219                                 mi, invokestatic);
220
221         /* impose loading constraints */
222
223         if (result == resolveSucceeded) {
224                 /* XXX state->m->class may have to be wrong when inlining */
225                 if (!resolve_method_loading_constraints(state->m->class, mi))
226                         return false;
227         }
228
229         if (result == resolveFailed)
230                 return false;
231
232         if (result == resolveSucceeded) {
233                 /* if this call is monomorphic, turn it into an INVOKESPECIAL */
234
235                 if ((state->iptr->opc == ICMD_INVOKEVIRTUAL)
236                         && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
237                 {
238                         state->iptr->opc = ICMD_INVOKESPECIAL;
239                 }
240         }
241         else {
242                 /* resolution must be deferred */
243
244                 if (!um) {
245                         um = resolve_create_unresolved_method(state->m->class, state->m,
246                                         mref, 
247                                         state->iptr->opc == ICMD_INVOKESTATIC,
248                                         invokespecial);
249
250                         if (!um)
251                                 return false;
252                 }
253
254                 /* record subtype constraints for parameters */
255
256                 if (!invokestatic && !resolve_constrain_unresolved_method_instance(
257                                         um, state->m, 
258                                         &(VAR(state->iptr->sx.s23.s2.args[0])->typeinfo),
259                                         invokespecial))
260                         return false; /* XXX maybe wrap exception */
261
262                 if (!resolve_constrain_unresolved_method_params(
263                                         jd, um, state->m, state->iptr))
264                         return false; /* XXX maybe wrap exception */
265
266                 /* store the unresolved_method pointer */
267
268                 state->iptr->sx.s23.s3.um = um;
269                 state->iptr->flags.bits |= INS_FLAG_UNRESOLVED;
270         }
271
272         /* set the return type */
273
274         rtype = md->returntype.type;
275         if (rtype != TYPE_VOID) {
276                 dv->type = rtype;
277                 if (!typeinfo_init_from_typedesc(&(md->returntype),NULL,&(dv->typeinfo)))
278                         return false;
279         }
280 }
281
282 /*
283  * These are local overrides for various environment variables in Emacs.
284  * Please do not remove this and leave it at the end of the file, where
285  * Emacs will automagically detect them.
286  * ---------------------------------------------------------------------
287  * Local variables:
288  * mode: c
289  * indent-tabs-mode: t
290  * c-basic-offset: 4
291  * tab-width: 4
292  * End:
293  * vim:noexpandtab:sw=4:ts=4:filetype=c:
294  */