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