1 /* jit/parseRT.c - parser and print functions for Rapid Type Analyis
3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
5 M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
6 P. Tomsich, J. Wenninger
8 This file is part of CACAO.
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Carolyn Oates
29 $Id: parseRT.c 1553 2004-11-19 15:47:13Z carolyn $
34 Rapid Type Static Analysis of Java program
35 used -rt option is turned on either explicitly
36 or automatically with inlining of virtuals.
39 Methods called by NATIVE methods and classes loaded dynamically
40 cannot be found by parsing. The following files supply missing methods:
42 rtMissedIn0 - (provided) has the methods missed by every java program
43 rtMissed||mainClassName - is program specific.
45 A file rtMissed will be written by RT analysis of any methods missed.
47 This file can be renamed to rtMissed concatenated with the main class name.
52 inlining with virtuals should fail if the returned rtMissed is not empty.
54 mv rtMissed rtMissedhello
57 Results: (currently) with -stat see # methods marked used
65 #include "statistics.h"
70 #include "jit/parse.h"
71 #include "toolbox/list.h"
72 #include "toolbox/memory.h"
74 #include "parseRTstats.h"
76 static bool firstCall= true;
77 static list *rtaWorkList;
78 FILE *rtMissed; /* Methods missed during RTA parse of Main */
80 bool DEBUGinf = false;
82 bool DEBUGopcodes = false;
84 /*********************************************************************/
86 void addToRtaWorkList(methodinfo *meth, char *info) {
89 if (meth->methodUsed == USED) return;
91 if (!(meth->flags & ACC_ABSTRACT)) {
92 count_methods_marked_used++;
93 METHINFOt(meth,info,DEBUGopcodes)
94 if (meth->class->super != NULL) {
95 CLASSNAME(meth->class->super,"\tsuper=",DEBUGr)
98 if (DEBUGr) printf("\tsuper=NULL\n");}
100 meth ->methodUsed = USED;
103 list_addlast(rtaWorkList,rta);
104 if (meth->class->classUsed == NOTUSED) {
106 printf("\nADDED method in class not used at all!\n");
112 printf("Method not added to work list!!!<%i> : ",
113 meth->methodUsed); fflush(stdout);
119 /**************************************************************************/
120 void rtaMarkSubs(classinfo *class, methodinfo *topmethod);
122 /*------------------------------------------------------------------------*/
123 void rtaAddUsedInterfaceMethods(classinfo *ci) {
126 /* add used interfaces methods to callgraph */
127 for (jj=0; jj < ci -> interfacescount; jj++) {
128 classinfo *ici = ci -> interfaces [jj];
131 printf("BInterface used: ");fflush(stdout);
132 utf_display(ici->name);
133 printf("<%i>\t",ici -> classUsed ); fflush(stdout);
134 if (ici -> classUsed == NOTUSED) printf("\t classUsed=NOTUSED\n" );
135 if (ici -> classUsed == USED) printf("\t classUsed=USED\n");
136 if (ici -> classUsed == PARTUSED) printf("\t classUsed=PARTUSED\n");
139 /* add class to interfaces list of classes that implement it */
140 ici -> impldBy = addElement(ici -> impldBy, ci);
142 /* if interface class is used */
143 if (ici -> classUsed != NOTUSED) {
145 /* for each interface method implementation that has already been used */
146 for (mm=0; mm< ici->methodscount; mm++) {
147 methodinfo *imi = &(ici->methods[mm]);
149 if (imi->methodUsed != USED) {
150 if (imi->methodUsed == NOTUSED) printf("Interface Method notused: ");
151 if (imi->methodUsed == MARKED) printf("Interface Method marked: ");
152 utf_display(ici->name);printf(".");method_display(imi);fflush(stdout);
155 if (imi->methodUsed == USED) {
157 printf("Interface Method used: "); utf_display(ici->name);printf(".");method_display(imi);fflush(stdout);
159 /* Mark this method used in the (used) implementing class and its subclasses */
160 printf("rMAY ADD methods that was used by an interface\n");
162 if ((utf_new_char("<clinit>") != imi->name) &&
163 (utf_new_char("<init>") != imi->name))
172 /**************************************************************************/
173 /* Add Marked methods for input class ci */
174 /* Add methods with the same name and descriptor as implemented interfaces*/
175 /* with the same method name */
177 /*------------------------------------------------------------------------*/
178 void rtaAddMarkedMethods(classinfo *ci) {
181 /* add marked methods to callgraph */
182 for (ii=0; ii<ci->methodscount; ii++) {
183 methodinfo *mi = &(ci->methods[ii]);
185 if (mi->methodUsed == MARKED) {
187 "addTo was MARKED:");
190 for (jj=0; jj < ci -> interfacescount; jj++) {
191 classinfo *ici = ci -> interfaces [jj];
192 /* use resolve method....!!!! */
193 if (ici -> classUsed != NOTUSED) {
194 for (mm=0; mm< ici->methodscount; mm++) {
195 methodinfo *imi = &(ici->methods[mm]);
196 METHINFOt(imi,"NEW IMPD INTERFACE:",DEBUGinf)
197 /*if interface method=method is used*/
198 if ( (imi->methodUsed == USED)
199 && ( (imi->name == mi->name)
200 && (imi->descriptor == mi->descriptor))) {
202 "addTo was interfaced used/MARKED:");
212 /*********************************************************************/
213 void addClassInit(classinfo *ci, bool clinits, bool finalizes, bool addmark)
218 ci->classUsed = USED;
220 if (clinits) { /* No <clinit> available - ignore */
221 mi = class_findmethod(ci,
222 utf_new_char("<clinit>"),
223 utf_new_char("()V"));
225 if (ci->classUsed != USED)
226 ci->classUsed = PARTUSED;
228 addToRtaWorkList(mi,"addTo CLINIT added:");
232 /*Special Case for System class init:
233 add java/lang/initializeSystemClass to callgraph */
234 if (ci->name == utf_new_char("initializeSystemClass")) {
235 /* ?? what is name of method ?? */
239 mi = class_findmethod(ci,
240 utf_new_char("finalize"),
241 utf_new_char("()V"));
243 if (ci->classUsed != USED)
244 ci->classUsed = PARTUSED;
246 addToRtaWorkList(mi,"addTo FINALIZE added:");
251 rtaAddMarkedMethods(ci);
252 rtaAddUsedInterfaceMethods(ci);
258 /*--------------------------------------------------------------*/
259 /* Mark the method with same name /descriptor in topmethod */
262 /* Class marked USED and method defined in this class -> */
263 /* -> mark method as USED */
264 /* Class not marked USED and method defined in this class -> */
265 /* -> if Method NOTUSED mark method as MARKED */
267 /* Class USED, but method not defined in this class -> */
268 /* -> 1) search up the heirarchy and mark method where defined */
269 /* 2) if class where method is defined is not USED -> */
270 /* -> mark class with defined method as PARTUSED */
271 /*--------------------------------------------------------------*/
273 void rtaMarkMethod(classinfo *class, methodinfo *topmethod) {
275 utf *name = topmethod->name;
276 utf *descriptor = topmethod->descriptor;
279 /* See if method defined in class heirarchy */
280 submeth = class_resolvemethod(class, name, descriptor);
281 METHINFOt(submeth,"rtaMarkMethod submeth:",DEBUGr);
282 if (submeth == NULL) {
283 utf_display(class->name); printf(".");
284 METHINFOx(topmethod);
285 printf("parse RT: Method not found in class hierarchy");fflush(stdout);
286 panic("parse RT: Method not found in class hierarchy");
288 if (submeth->methodUsed == USED) return;
292 /* Class Type Analysis if class.method in virt cone marks it used */
293 /* very inexact, too many extra methods */
294 addClassInit( submeth->class,
296 submeth->monoPoly = POLY;
297 addToRtaWorkList(submeth,
298 "addTo RTA VIRT CONE:");
302 if (submeth->class == class) {
304 /*--- Method defined in class -----------------------------*/
305 if ( submeth->class->classUsed == USED) {
306 /* method defined in this class -> */
307 /* Class IS marked USED */
308 /* -> mark method as USED */
309 submeth->monoPoly = POLY;
310 addToRtaWorkList(submeth,
311 "addTo VIRT CONE 1:");
314 /* method defined in this class -> */
315 /* Class IS NOT marked USED (PART or NOTUSED) */
316 /* -> if Method NOTUSED mark method as MARKED */
318 "\tmarked VIRT CONE 2:",DEBUGr);
319 submeth->monoPoly = POLY;
320 submeth->methodUsed = MARKED;
321 /* Note: if class NOTUSED and subclass is used handled */
322 /* by subsequent calls to rtaMarkMethods for cone */
324 } /* end defined in class */
327 /*--- Method NOT defined in class ---------------*/
328 /* first mark classes if needed */
329 if (submeth->class->classUsed == NOTUSED) {
330 submeth->class->classUsed = PARTUSED;
331 if (class->classUsed != USED) {
332 submeth->monoPoly = POLY;
333 submeth->methodUsed = MARKED;
334 METHINFOt(submeth,"JUST MARKED :",DEBUGr);
337 /* add method to rta work list if conditions met */
338 /*??if ( (submeth->class->classUsed == USED) || */
339 if (class->classUsed == USED) {
340 submeth->monoPoly = POLY;
341 addToRtaWorkList(submeth,
342 "addTo VIRT CONE 3:");
344 } /* end NOT defined in class */
348 /*----------------------------------------------------------------------*/
349 /* Mark the method with the same name and descriptor as topmethod */
350 /* and any subclass where the method is defined and/or class is used */
352 /*----------------------------------------------------------------------*/
353 void rtaMarkSubs(classinfo *class, methodinfo *topmethod) {
355 /* Mark method in class */
356 CLASSNAME1(class," MARKSUBS ",DEBUGr);
357 METHINFOt(topmethod," TOP ",DEBUGr);
358 rtaMarkMethod(class, topmethod);
360 /* Mark method in subclasses */
361 if (class->sub != NULL) {
364 if (!(topmethod->flags & ACC_FINAL )) {
365 for (subs = class->sub;subs != NULL;subs = subs->nextsub) {
366 CLASSNAME1(subs," SUBS ",DEBUGr);
367 rtaMarkSubs(subs, topmethod);
375 /*********************************************************************/
377 void rtaMarkInterfaceSubs(methodinfo *mi) {
379 if (mi->class->classUsed == NOTUSED) {
380 mi->class->classUsed = USED;
381 class_java_lang_Object->impldBy = addElement(class_java_lang_Object -> impldBy, mi->class);
384 /* add interface class to list kept in Object */
385 mi->methodUsed = USED;
388 subs = mi->class->impldBy;
389 /*RTAPRINT08invokeInterface1*/
391 METHINFO(mi,DEBUGinf)
392 printf("Implemented By classes :\n");fflush(stdout);
393 if (subs == NULL) printf("\tNOT IMPLEMENTED !!!\n");
396 while (subs != NULL) {
397 classinfo * isubs = subs->classType;
400 printf("\t");utf_display(isubs->name);fflush(stdout);
401 printf(" <%i>\n",isubs->classUsed);fflush(stdout);
403 /*Mark method (mark/used) in classes that implement method*/
405 submeth = class_findmethod(isubs,mi->name, mi->descriptor);
407 submeth->monoPoly = POLY; /* poly even if nosubs */
408 rtaMarkSubs(isubs, mi);
410 subs = subs->nextClass;
415 /*********************************************************************/
417 int parseRT(methodinfo *m)
419 int p; /* java instruction counter */
420 int nextp; /* start of next java instruction */
421 int opcode; /* java opcode */
422 int i; /* temp for different uses (counters)*/
423 bool iswide = false; /* true if last instruction was a wide*/
426 METHINFOt(m,"\n----RT PARSING:",DEBUGopcodes);
427 if ((DEBUGr)||(DEBUGopcodes)) printf("\n");
429 /* scan all java instructions */
430 for (p = 0; p < m->jcodelength; p = nextp) {
432 opcode = code_get_u1(p,m); /* fetch op code */
435 nextp = p + jcommandsize[opcode]; /* compute next instrtart */
436 if (nextp > m->jcodelength)
437 panic("Unexpected end of bytecode");
469 /* wider index for loading, storing and incrementing */
483 case JAVA_LOOKUPSWITCH:
486 nextp = ALIGN((p + 1), 4) + 4;
487 num = code_get_u4(nextp,m);
488 nextp += (code_get_u4(nextp,m)) * 8 + 4;
493 case JAVA_TABLESWITCH:
496 nextp = ALIGN ((p + 1),4);
497 num = code_get_s4(nextp + 4, m);
498 num = code_get_s4(nextp + 8, m) - num;
499 nextp = nextp + 16 + 4 * num;
502 /*********************/
506 i = code_get_u2(p + 1,m);
511 fr = class_getconstant(m->class, i, CONSTANT_Fieldref);
512 LAZYLOADING(fr->class)
514 fi = class_resolvefield(fr->class,
521 return 0; /* was NULL */
523 CLASSNAME(fi->class,"\tPUT/GETSTATIC: ",DEBUGr);
524 if (!fi->class->initialized) {
525 m->isleafmethod = false;
527 addClassInit( fi->class,
532 case JAVA_INVOKESTATIC:
533 case JAVA_INVOKESPECIAL:
534 i = code_get_u2(p + 1,m);
539 m->isleafmethod = false;
540 mr = class_getconstant(m->class, i, CONSTANT_Methodref);
541 LAZYLOADING(mr->class)
542 mi = class_resolveclassmethod(mr->class,
551 METHINFOt(mi,"INVOKESTAT/SPEC:: ",DEBUGopcodes)
553 if ((opcode == JAVA_INVOKESTATIC)
554 || (mi->flags & ACC_STATIC)
555 || (mi->flags & ACC_PRIVATE)
556 || (mi->flags & ACC_FINAL) )
558 if (mi->class->classUsed == PARTUSED){
559 addClassInit(mi->class,
563 if (mi->class->classUsed == NOTUSED){
564 addClassInit(mi->class,
566 if (mi->class->classUsed == NOTUSED){
567 mi->class->classUsed = PARTUSED; }
570 if (opcode == JAVA_INVOKESTATIC)
572 "addTo INVOKESTATIC ");
575 "addTo INVOKESPECIAL ");
578 /* Handle special <init> calls */
580 /* for now same as rest */
581 if (mi->class->classUsed != USED){
583 call of super's <init> then
584 methods of super class not all used */
585 if (utf_new_char("<init>")==mi->name) {
586 if (m->class->super == mi->class) {
587 METHINFOt(mi,"SUPER INIT:",DEBUGopcodes);
589 addClassInit(mi->class,
591 if (mi->class->classUsed == NOTUSED) mi->class->classUsed = PARTUSED;
594 METHINFOt(mi,"NORMAL INIT:",DEBUGopcodes);
595 addClassInit(mi->class,
601 if (utf_new_char("<clinit>")==mi->name)
602 addClassInit( mi->class,
605 if (!((utf_new_char("<init>")==mi->name))
606 || (utf_new_char("<clinit>")==mi->name)) {
607 METHINFOt(mi,"SPECIAL not init:",DEBUGopcodes)
608 if (mi->class->classUsed !=USED)
609 mi->class->classUsed = PARTUSED;
611 "addTo SPEC notINIT ");
615 "addTo SPEC whymissed ");
619 /*** assume if method can't be resolved won't actually be called or
620 there is a real error in classpath and in normal parse an exception
621 will be thrown. Following debug print can verify this
623 CLASSNAME1(mr->class,"CouldNOT Resolve method:",,DEBUGr);printf(".");fflush(stdout);
624 utf_display(mr->name); printf(" "); fflush(stdout);
625 utf_display(mr->descriptor); printf("\n");fflush(stdout);
630 case JAVA_INVOKEVIRTUAL:
631 i = code_get_u2(p + 1,m);
636 m->isleafmethod = false;
637 mr = m->class->cpinfos[i];
638 /*mr = class_getconstant(m->class, i, CONSTANT_Methodref)*/
639 LAZYLOADING(mr->class)
640 mi = class_resolveclassmethod(mr->class,
649 METHINFOt(mi,"INVOKEVIRTUAL ::",DEBUGopcodes);
650 if ((mi->flags & ACC_STATIC)
651 || (mi->flags & ACC_PRIVATE)
652 || (mi->flags & ACC_FINAL) )
654 if (mi->class->classUsed == NOTUSED){
655 addClassInit(mi->class,
660 "addTo INVOKEVIRTUAL ");
664 rtaMarkSubs(mi->class,mi);
668 CLASSNAME1(mr->class,"CouldNOT Resolve virt meth:",DEBUGr);printf(".");fflush(stdout);
669 utf_display(mr->name); printf(" "); fflush(stdout);
670 utf_display(mr->descriptor); printf("\n");fflush(stdout);
675 case JAVA_INVOKEINTERFACE:
676 i = code_get_u2(p + 1,m);
681 m->isleafmethod = false;
683 mr = class_getconstant(m->class, i, CONSTANT_InterfaceMethodref);
684 LAZYLOADING(mr->class)
686 mi = class_resolveinterfacemethod(mr->class,
693 METHINFOt(mi,"\tINVOKEINTERFACE: ",DEBUGopcodes)
694 rtaMarkInterfaceSubs(mi);
696 /* see INVOKESTATIC for explanation about */
697 /* case when Interface is not resolved */
698 /*descriptor2types(mi);
699 ?? do need paramcnt? for RTA (or just XTA)*/
704 /* means class is at least passed as a parameter */
705 /* class is really instantiated when class.<init> called*/
706 i = code_get_u2(p + 1,m);
709 ci = class_getconstant(m->class, i, CONSTANT_Class);
710 m->isleafmethod = false; /* why for new ? */
711 /*** s_count++; look for s_counts for VTA */
712 /***ci->classUsed=USED; */
713 /* add marked methods */
714 CLASSNAME(ci,"NEW : do nothing",DEBUGr);
715 addClassInit(ci, true, true, true);
720 case JAVA_INSTANCEOF:
722 i = code_get_u2(p + 1,m);
726 class_getconstant(m->class, i, CONSTANT_Class);
728 CLASSNAMEop(cls,DEBUGr);
729 if (cls->classUsed == NOTUSED){
746 /* Helper fn for initialize **********************************************/
748 int getline(char *line, int max, FILE *inFP) {
749 if (fgets(line, max, inFP) == NULL)
752 return strlen((const char *) line);
755 /* Initialize RTA Work list ***********************************************/
757 /*-- Get meth ptr for class.meth desc and add to RTA worklist --*/
758 #define SYSADD(cls,meth,desc,txt) \
759 c = class_new(utf_new_char(cls)); \
761 callmeth = class_resolveclassmethod(c, \
762 utf_new_char(meth), \
763 utf_new_char(desc), \
766 if (callmeth->class->classUsed != USED) { \
767 c->classUsed = PARTUSED; \
768 addClassInit(callmeth->class, \
771 callmeth->monoPoly = POLY; \
772 addToRtaWorkList(callmeth,txt);
776 Initialize RTA work list with methods/classes from:
779 rtMissedIn list (missed becaused called from NATIVE &/or dynamic calls
781 methodinfo *initializeRTAworklist(methodinfo *m) {
783 methodinfo* callmeth;
784 char systxt[] = "System Call :";
785 char missedtxt[] = "rtMissedIn Call :";
787 FILE *rtMissedIn; /* Methods missed during previous RTA parse */
789 char* class, *meth, *desc;
790 methodinfo *rm =NULL; /* return methodinfo ptr to main method */
793 /* Create RTA call work list */
794 rtaWorkList = NEW(list);
795 list_init(rtaWorkList, OFFSET(rtaNode,linkage) );
797 /* Add first method to call list */
798 m->class->classUsed = USED;
799 addToRtaWorkList(m,systxt);
801 /* Add system called methods */
802 SYSADD(mainstring, "main","([Ljava/lang/String;)V",systxt)
804 SYSADD("java/lang/Runtime","getRuntime","()Ljava/lang/Runtime;",systxt)
805 SYSADD("java/lang/System","exit","(I)V",systxt)
806 /*----- rtMissedIn 0 */
807 if ( (rtMissedIn = fopen("rtMissedIn0", "r")) == NULL) {
808 /*if (opt_verbose) */
809 {printf("No rtMissedIn0 file\n");fflush(stdout);}
812 while (getline(line,256,rtMissedIn)) {
813 class = strtok(line, " \n");
814 meth = strtok(NULL, " \n");
815 desc = strtok(NULL, " \n");
816 SYSADD(class,meth,desc,missedtxt)
827 /*- end initializeRTAworklist-------- */
831 methodinfo *missedRTAworklist()
833 FILE *rtMissedIn; /* Methods missed during previous RTA parse */
834 char filenameIn[256] = "rtIn/";
836 char* class, *meth, *desc;
837 char missedtxt[] = "rtIn/ missed Call :";
839 methodinfo* callmeth;
841 methodinfo *rm =NULL; /* return methodinfo ptr to main method */
843 /*----- rtMissedIn pgm specific */
844 strcat(filenameIn, (const char *)mainstring);
845 if ( (rtMissedIn = fopen(filenameIn, "r")) == NULL) {
847 {printf("No rtIn/=%s file\n",filenameIn);fflush(stdout);}
850 while (getline(line,256,rtMissedIn)) {
851 class = strtok(line, " \n");
852 meth = strtok(NULL, " \n");
853 desc = strtok(NULL, " \n");
854 if ((class == NULL) || (meth == NULL) || (desc == NULL)) {
855 fprintf(stderr,"Error in rtMissedIn file for: %s.%s %s\n",class, meth, desc);
857 panic ("Error in rtMissedIn file for: class.meth, desc\n");
859 SYSADD(class,meth,desc,missedtxt)
867 /*--------------------------------------------------------*/
869 /* input: method to be RTA static parsed */
870 /*--------------------------------------------------------*/
871 void parseRTmethod(methodinfo *rt_method) {
872 if (! ( (rt_method->flags & ACC_NATIVE )
873 || (rt_method->flags & ACC_ABSTRACT) ) )
875 /* RTA parse to approxmate....
876 what classes/methods will really be used during execution */
880 if (rt_method->flags & ACC_NATIVE )
882 METHINFOt(rt_method,"TO BE NATIVE RTA PARSED :",DEBUGopcodes);
883 /* parseRTpseudo(rt_method); */
886 printf("Abstract method in RTA Work List: ");
887 METHINFOx(rt_method);
888 panic("Abstract method in RTA Work List.");
894 /*-- RTA -- *******************************************************/
895 int RT_jit_parse(methodinfo *m)
898 methodinfo *mainmeth;
900 /* Should only be called once */
903 /*----- RTA initializations --------*/
905 log_text("RTA static analysis started.\n");
907 mainmeth = initializeRTAworklist(m);
908 firstCall = false; /* turn flag off */
910 if ( (rtMissed = fopen("rtMissed", "w")) == NULL) {
911 printf("CACAO - rtMissed file: cant open file to write\n");
913 /* Note: rtMissed must be renamed to rtMissedIn to be used as input */
915 /*------ process RTA call work list --------*/
916 for (rta =list_first(rtaWorkList);
918 rta =list_next(rtaWorkList,rta))
920 parseRTmethod(rta->method);
923 for (rta =list_first(rtaWorkList);
925 rta =list_next(rtaWorkList,rta))
927 parseRTmethod(rta->method);
933 printRThierarchyInfo(m);
935 printCallgraph(rtaWorkList);
939 log_text("RTA static analysis done.\n");
946 * These are local overrides for various environment variables in Emacs.
947 * Please do not remove this and leave it at the end of the file, where
948 * Emacs will automagically detect them.
949 * ---------------------------------------------------------------------
952 * indent-tabs-mode: t