LCOV - code coverage report
Current view: top level - vm/jit/verify - typecheck-invoke.inc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 86 114 75.4 %
Date: 2017-07-14 10:03:36 Functions: 0 0 -

          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             :  */

Generated by: LCOV version 1.11