CACAO
typecheck-invoke.inc
Go to the documentation of this file.
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  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  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  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  if (INSTRUCTION_IS_UNRESOLVED(state->iptr)) {
58  /* unresolved method */
59  um = state->iptr->sx.s23.s3.um;
60  mref = um->methodref;
61  }
62  else {
63  /* resolved method */
64  um = NULL;
65  mref = state->iptr->sx.s23.s3.fmiref;
66  }
67 
68  /* get method descriptor and name */
69 
70  md = mref->parseddesc.md;
71  mname = mref->name;
72 
73 #if !defined(TYPECHECK_TYPEINFERER)
74  /* get method info (if resolved) and classname */
75 
76  if (mref->is_resolved()) {
77  mi = mref->p.method;
78  mclassname = mi->clazz->name;
79  }
80  else {
81  mi = NULL;
82  mclassname = mref->p.classref->name;
83  }
84 
85  /* gather some info about this instruction */
86 
87  opcode = state->iptr->opc;
88  invokestatic = (opcode == ICMD_INVOKESTATIC);
89  invokespecial = (opcode == ICMD_INVOKESPECIAL);
90  specialmethod = (mname[0] == '<');
91 
92  /* prevent compiler warnings */
93 
94  ins = NULL;
95 
96  /* check whether we are calling <init> */
97 
98  callinginit = (invokespecial && mname == utf8::init);
99  if (specialmethod && !callinginit)
100  TYPECHECK_VERIFYERROR_bool("Invalid invocation of special method");
101 
102  /* allocate parameters if necessary */
103 
104  md->params_from_paramtypes(invokestatic ? ACC_STATIC : ACC_NONE);
105 
106  /* check parameter types */
107 
108 #if defined(TYPECHECK_STACKBASED)
109  av = stack - (md->paramslots - 1);
110  for (i=0; i<md->paramcount; ++i) {
111 #else
112  i = md->paramcount; /* number of parameters including 'this'*/
113  while (--i >= 0) {
114  argindex = state->iptr->sx.s23.s2.args[i];
115  av = VAR(argindex);
116 #endif
117  OLD_LOG1("\t\tparam %d",i);
118  td = md->paramtypes + i;
119 
120  if (av->type != td->type)
121  TYPECHECK_VERIFYERROR_bool("Parameter type mismatch in method invocation");
122 
123  if (av->type == TYPE_ADR) {
124  OLD_LOGSTR("\t\t"); OLD_LOGINFO(&(av->typeinfo));
125  if (i==0 && callinginit)
126  {
127  /* first argument to <init> method */
128  if (!av->typeinfo.is_newobject())
129  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  ins = av->typeinfo.newobject_instruction();
134  if (ins)
135  initclass = ins[-1].sx.val.c;
136  else
137  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  if (i==0 && !invokestatic) {
145  TYPECHECK_VERIFYERROR_bool("Parameter type mismatch for 'this' argument");
146  }
147  }
148  OLD_LOG("\t\tok");
149 
150 #if defined(TYPECHECK_STACKBASED)
151  av += (IS_2_WORD_TYPE(av->type)) ? 2 : 1;
152 #endif
153  }
154 
155  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  for (i=0; i<state->iptr->s1.argcount; ++i) {
162  argindex = state->iptr->sx.s23.s2.args[i];
163  av = VAR(argindex);
164 #else
165  for (av=stackfloor; av <= stack; ++av) {
166 #endif
167  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  if (state->bptr->invars
180  && argindex >= state->bptr->invars[0]
181  && argindex < state->bptr->varstart
182  && !state->savedinvars)
183  {
184  typestate_save_invars(state);
185  }
186 #endif /* defined(TYPECHECK_VARIABLESBASED) */
187 
188  if (!av->typeinfo.init_class(initclass))
189  return false;
190  }
191  }
192 
193  /* replace uninitialized object type in locals */
194 #if defined(TYPECHECK_VARIABLESBASED)
195  if (!typevector_init_object(state->jd->var, ins, initclass,
196  state->numlocals))
197  return false;
198 #else
199  /* XXX should reuse typevector code */
200  for (i=0; i<state->numlocals; ++i) {
201  if (state->locals[i].type == TYPE_ADR
202  && state->locals[i].typeinfo.is_newobject()
203  && state->locals[i].typeinfo.newobject_instruction() == ins)
204  {
205  if (!state->locals[i].typeinfo.init_class(initclass))
206  return false;
207  }
208  }
209 #endif
210 
211  /* initializing the 'this' reference? */
212  if (!ins) {
213  classinfo *cls;
214  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  if (mi) {
220  cls = mi->clazz;
221  }
222  else {
223  if (!resolve_classref(state->m,mref->p.classref,resolveLazy,false,true,&cls))
224  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  if (cls == NULL || (cls != state->m->clazz && cls != state->m->clazz->super)) {
230  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  typevector_store(jd->var, state->numlocals-1, TYPE_INT, NULL);
237 #else
238  state->locals[state->numlocals-1].type = TYPE_INT;
239 #endif
240  }
241  else {
242  /* { we are initializing an instance created with NEW } */
243  if (CLASSREF_OR_CLASSINFO_NAME(initclass) != mclassname) {
244  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  result = resolve_method_lazy(state->m, mref, invokespecial);
252 
253  /* perform verification checks */
254 
255  if (result == resolveSucceeded) {
256 
257  assert(mref->is_resolved());
258 
259  mi = mref->p.method;
260 
261  result = resolve_method_verifier_checks(state->m,
262  mref,
263  mi,
264  invokestatic);
265  }
266 
267  /* check types of parameters */
268 
269  if (result == resolveSucceeded && !invokestatic)
271  state->m, mi,
272  &(OP1->typeinfo),
273  invokespecial);
274 
275 #if defined(TYPECHECK_VARIABLESBASED)
276  if (result == resolveSucceeded)
278  jd, state->m, state->iptr,
279  mi, invokestatic);
280 #else
281  if (result == resolveSucceeded)
283  state->m, mi, invokestatic, stack);
284 #endif
285 
286  /* impose loading constraints */
287 
288  if (result == resolveSucceeded) {
289  /* XXX state->m->clazz may have to be wrong when inlining */
290  if (!resolve_method_loading_constraints(state->m->clazz, mi))
291  return false;
292  }
293 
294  if (result == resolveFailed)
295  return false;
296 
297  if (result == resolveSucceeded) {
298  /* if this call is monomorphic, turn it into an INVOKESPECIAL */
299 
300  if ((state->iptr->opc == ICMD_INVOKEVIRTUAL)
301  && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
302  {
303  state->iptr->opc = ICMD_INVOKESPECIAL;
304  state->iptr->flags.bits |= INS_FLAG_CHECK;
305  }
306  }
307  else {
308  /* resolution must be deferred */
309 
310  if (!um) {
311  um = resolve_create_unresolved_method(state->m->clazz, state->m,
312  mref,
313  invokestatic,
314  invokespecial);
315 
316  if (!um)
317  return false;
318  }
319 
320  /* record subtype constraints for parameters */
321 
322  if (!invokestatic && !resolve_constrain_unresolved_method_instance(
323  um, state->m,
324  &(OP1->typeinfo),
325  invokespecial))
326  return false; /* XXX maybe wrap exception */
327 
328 #if defined(TYPECHECK_VARIABLESBASED)
330  jd, um, state->m, state->iptr))
331  return false; /* XXX maybe wrap exception */
332 #else
334  um, state->m, stack))
335  return false; /* XXX maybe wrap exception */
336 #endif
337 
338  /* store the unresolved_method pointer */
339 
340  state->iptr->sx.s23.s3.um = um;
341  state->iptr->flags.bits |= INS_FLAG_UNRESOLVED;
342  }
343 #endif /* !defined(TYPECHECK_TYPEINFERER) */
344 
345  /* set the return type */
346 
347  rtype = md->returntype.type;
348  if (rtype != TYPE_VOID) {
349  dv->type = rtype;
350  if (!dv->typeinfo.init_from_typedesc(&md->returntype, NULL))
351  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  */
val_operand_t val
#define OLD_LOG(str)
typeinfo_t typeinfo
Definition: typeinfo.hpp:382
void init_class(classinfo *c)
Initialize object type.
Definition: typeinfo.cpp:790
resolve_result_t resolve_method_verifier_checks(methodinfo *refmethod, constant_FMIref *methodref, methodinfo *mi, bool invokestatic)
Definition: resolve.cpp:1597
bool resolve_constrain_unresolved_method_params(jitdata *jd, unresolved_method *ref, methodinfo *refmethod, instruction *iptr)
Definition: resolve.cpp:2713
classinfo * super
Definition: class.hpp:102
unresolved_method * resolve_create_unresolved_method(classinfo *referer, methodinfo *refmethod, constant_FMIref *methodref, bool invokestatic, bool invokespecial)
Definition: resolve.cpp:2596
bool resolve_classref(methodinfo *refmethod, constant_classref *ref, resolve_mode_t mode, bool checkaccess, bool link, classinfo **result)
Definition: resolve.cpp:309
#define OLD_LOGINFO(info)
bool is_newobject() const
Definition: typeinfo.hpp:246
union constant_FMIref::@26 p
methoddesc * md
Definition: references.hpp:75
methodinfo * method
Definition: references.hpp:101
const Utf8String name
Definition: references.hpp:103
#define TYPECHECK_ASSERT(cond)
#define OLD_LOG1(str, a)
bool resolve_constrain_unresolved_method_instance(unresolved_method *ref, methodinfo *refmethod, typeinfo_t *instanceti, bool invokespecial)
Definition: resolve.cpp:2648
#define VAR(i)
Definition: jit.hpp:252
Definition: reg.hpp:43
bool resolve_constrain_unresolved_method_params_stackbased(unresolved_method *ref, methodinfo *refmethod, typedescriptor_t *stack)
Definition: resolve.cpp:2788
typedesc paramtypes[1]
Definition: descriptor.hpp:167
bool typevector_init_object(varinfo *set, void *ins, classref_or_classinfo initclass, int size)
Definition: typeinfo.cpp:245
#define IS_2_WORD_TYPE(a)
Definition: global.hpp:132
resolve_result_t resolve_method_instance_type_checks(methodinfo *refmethod, methodinfo *mi, typeinfo_t *instanceti, bool invokespecial)
Definition: resolve.cpp:1680
classref_or_classinfo c
resolve_result_t resolve_method_lazy(methodinfo *refmethod, constant_FMIref *methodref, bool invokespecial)
Definition: resolve.cpp:1950
bool is_resolved() const
Definition: references.hpp:107
#define OLD_LOGNL
classinfo * clazz
Definition: method.hpp:80
alloc::list< PassInfo::IDTy >::type & stack
Utf8String name
Definition: class.hpp:91
Type
Types used internally by JITTED code.
Definition: global.hpp:117
#define TYPECHECK_VERIFYERROR_bool(msg)
MIIterator i
Fieldref, Methodref and InterfaceMethodref.
Definition: references.hpp:86
typedesc returntype
Definition: descriptor.hpp:166
int32_t s4
Definition: types.hpp:45
union instruction::@12 sx
#define CLASSREF_OR_CLASSINFO_NAME(value)
Definition: references.hpp:194
instruction * newobject_instruction() const
Definition: typeinfo.hpp:254
void params_from_paramtypes(s4 mflags)
Definition: descriptor.cpp:877
#define OLD_LOGNAME(c)
static void typestate_save_invars(verifier_state *state)
Definition: typecheck.cpp:223
resolve_result_t resolve_method_param_type_checks_stackbased(methodinfo *refmethod, methodinfo *mi, bool invokestatic, typedescriptor_t *stack)
Definition: resolve.cpp:1813
constant_FMIref * methodref
Definition: resolve.hpp:97
#define OP1
void typevector_store(varinfo *vec, int index, Type type, typeinfo_t *info)
Definition: typeinfo.cpp:195
#define OLD_LOGSTR(str)
constant_classref * classref
Definition: references.hpp:97
#define INSTRUCTION_IS_UNRESOLVED(iptr)
const parseddesc_t parseddesc
Definition: references.hpp:105
s4 flags
Definition: method.hpp:70
bool resolve_method_loading_constraints(classinfo *referer, methodinfo *mi)
Definition: resolve.cpp:1876
resolve_result_t resolve_method_param_type_checks(jitdata *jd, methodinfo *refmethod, instruction *iptr, methodinfo *mi, bool invokestatic)
Definition: resolve.cpp:1748
resolve_result_t
Definition: resolve.hpp:67
const Utf8String name
Definition: references.hpp:48