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 1494 2004-11-12 13:34:26Z twisti $
32 opcode put into functions
33 changed class_findmethod class_fetchmethod
40 Methods called by NATIVE methods and classes loaded dynamically
41 cannot be found by parsing. The following files supply missing methods:
43 rtMissedIn0 - (provided) has the methods missed by every java program
44 rtMissed||mainClassName - is program specific.
46 A file rtMissed will be written by RT analysis of any methods missed.
48 This file can be renamed to rtMissed concatenated with the main class name.
53 inlining with virtuals should fail if the returned rtMissed is not empty.
55 mv rtMissed rtMissedhello
58 Results: (currently) with -stat see # methods marked used
60 TODO: end analysis if mono- or polymorphic call (in parseRTstats)
67 #include "statistics.h"
72 #include "jit/parse.h"
73 #include "toolbox/list.h"
74 #include "toolbox/memory.h"
76 #include "parseRTstats.h"
78 static bool firstCall= true;
79 static list *rtaWorkList;
80 FILE *rtMissed; /* Methods missed during RTA parse of Main */
82 #define LAZYLOADING(class) { \
83 if (!class_load(class)) \
85 if (!class_link(class)) \
89 bool DEBUGopcodes = false;
91 #define METHINFO(mm) \
92 if (DEBUGr == true) { \
93 printf("<c%i/m%i/p%i>\t", \
94 mm->class->classUsed,mm->methodUsed, mm->monoPoly); \
95 utf_display(mm->class->name); printf("."); fflush(stdout); \
96 method_display(mm); fflush(stdout); }
98 #define METHINFOt(mm,TXT) \
99 if (DEBUGr == true) { \
101 printf("<c%i/m%i/p%i>\t", \
102 mm->class->classUsed,mm->methodUsed, mm->monoPoly); \
103 utf_display(mm->class->name); printf("."); fflush(stdout); \
104 method_display(mm); fflush(stdout); }
106 #define CLASSNAME1(cls,TXT) \
107 if (DEBUGr == true) {printf(TXT); \
108 printf("<c%i>\t",cls->classUsed); \
109 utf_display(cls->name); fflush(stdout);}
111 #define CLASSNAMEop(cls) \
112 if (DEBUGr == true) {printf("\t%s: ",opcode_names[opcode]);\
113 printf("<c%i>\t",cls->classUsed); \
114 utf_display(cls->name); printf("\n");fflush(stdout);}
116 #define CLASSNAME(cls,TXT) \
117 if (DEBUGr == true) { printf(TXT); \
118 printf("<c%i>\t",cls->classUsed); \
119 utf_display(cls->name); printf("\n");fflush(stdout);}
122 if (DEBUGopcodes == true) {printf("Parse p=%i<%i< opcode=<%i> %s\n", \
123 p, m->jcodelength,opcode,opcode_names[opcode]);}
125 /*********************************************************************/
127 void addToRtaWorkList(methodinfo *meth, char *info) {
130 if (meth->methodUsed == USED) return;
132 if (!(meth->flags & ACC_ABSTRACT)) {
133 count_methods_marked_used++;
135 if (meth->class->super != NULL) {
136 CLASSNAME(meth->class->super,"\tsuper=")
139 if (DEBUGr) printf("\tsuper=NULL\n");}
141 meth ->methodUsed = USED;
144 list_addlast(rtaWorkList,rta);
145 if (meth->class->classUsed == NOTUSED) {
146 printf("\nADDED method in class not used at all!\n");
152 printf("Method not added to work list!!!<%i> : ",
153 meth->methodUsed); fflush(stdout);
159 /**************************************************************************/
160 /* Add Marked methods for input class ci */
161 /* Add methods with the same name and descriptor as implemented interfaces*/
162 /* with the same method name */
164 /*------------------------------------------------------------------------*/
165 void rtaAddMarkedMethods(classinfo *ci) {
168 /* add marked methods to callgraph */
169 for (ii=0; ii<ci->methodscount; ii++) {
170 methodinfo *mi = &(ci->methods[ii]);
172 if (mi->methodUsed == MARKED) {
174 "addTo was MARKED:");
177 for (jj=0; jj < ci -> interfacescount; jj++) {
178 classinfo *ici = ci -> interfaces [jj];
179 /* use resolve method....!!!! */
180 if (ici -> classUsed != NOTUSED) {
181 for (mm=0; mm< ici->methodscount; mm++) {
182 methodinfo *imi = &(ici->methods[mm]);
183 /*if interface method=method is used*/
184 if ( (imi->methodUsed == USED)
185 && ( (imi->name == mi->name)
186 && (imi->descriptor == mi->descriptor))) {
188 "addTo was interfaced used/MARKED:");
198 /*********************************************************************/
199 void addClassInit(classinfo *ci, bool clinits, bool finalizes, bool addmark)
204 ci->classUsed = USED;
206 if (clinits) { /* No <clinit> available - ignore */
207 mi = class_findmethod(ci,
208 utf_new_char("<clinit>"),
209 utf_new_char("()V"));
211 if (ci->classUsed != USED)
212 ci->classUsed = PARTUSED;
214 addToRtaWorkList(mi,"addTo CLINIT added:");
218 /*Special Case for System class init:
219 add java/lang/initializeSystemClass to callgraph */
220 if (ci->name == utf_new_char("initializeSystemClass")) {
221 /* ?? what is name of method ?? */
225 mi = class_findmethod(ci,
226 utf_new_char("finalize"),
227 utf_new_char("()V"));
229 if (ci->classUsed != USED)
230 ci->classUsed = PARTUSED;
232 addToRtaWorkList(mi,"addTo FINALIZE added:");
237 rtaAddMarkedMethods(ci);
243 /*--------------------------------------------------------------*/
244 /* Mark the method with same name /descriptor in topmethod */
247 /* Class marked USED and method defined in this class -> */
248 /* -> mark method as USED */
249 /* Class not marked USED and method defined in this class -> */
250 /* -> if Method NOTUSED mark method as MARKED */
252 /* Class USED, but method not defined in this class -> */
253 /* -> 1) search up the heirarchy and mark method where defined */
254 /* 2) if class where method is defined is not USED -> */
255 /* -> mark class with defined method as PARTUSED */
256 /*--------------------------------------------------------------*/
258 void rtaMarkMethod(classinfo *class, methodinfo *topmethod) {
260 utf *name = topmethod->name;
261 utf *descriptor = topmethod->descriptor;
264 /* See if method defined in class heirarchy */
265 submeth = class_resolvemethod(class, name, descriptor);
267 panic("parse RT: Method not found in class hierarchy");
268 if (submeth->methodUsed == USED) return;
272 /* Class Type Analysis if class.method in virt cone marks it used */
273 /* very inexact, too many extra methods */
274 addClassInit( submeth->class,
276 submeth->monoPoly = POLY;
277 addToRtaWorkList(submeth,
278 "addTo RTA VIRT CONE:");
282 if (submeth->class == class) {
284 /*--- Method defined in class -----------------------------*/
285 if ( submeth->class->classUsed == USED) {
286 /* method defined in this class -> */
287 /* Class IS marked USED */
288 /* -> mark method as USED */
289 submeth->monoPoly = POLY;
290 addToRtaWorkList(submeth,
291 "addTo VIRT CONE 1:");
294 /* method defined in this class -> */
295 /* Class IS NOT marked USED (PART or NOTUSED) */
296 /* -> if Method NOTUSED mark method as MARKED */
298 "\tmarked VIRT CONE 2:");
299 submeth->monoPoly = POLY;
300 submeth->methodUsed = MARKED;
301 /* Note: if class NOTUSED and subclass is used handled */
302 /* by subsequent calls to rtaMarkMethods for cone */
304 } /* end defined in class */
307 /*--- Method NOT defined in class ---------------*/
308 /* first mark classes if needed */
309 if (submeth->class->classUsed == NOTUSED) {
310 submeth->class->classUsed = PARTUSED;
311 if (class->classUsed != USED) {
312 submeth->monoPoly = POLY;
313 submeth->methodUsed = MARKED;
314 METHINFOt(submeth,"JUST MARKED :");
317 /* add method to rta work list if conditions met */
318 /* if ( (submeth->class->classUsed == USED) || */
319 if (class->classUsed == USED) {
320 submeth->monoPoly = POLY;
321 addToRtaWorkList(submeth,
322 "addTo VIRT CONE 3:");
324 } /* end NOT defined in class */
328 /*----------------------------------------------------------------------*/
329 /* Mark the method with the same name and descriptor as topmethod */
330 /* and any subclass where the method is defined and/or class is used */
332 /*----------------------------------------------------------------------*/
333 void rtaMarkSubs(classinfo *class, methodinfo *topmethod) {
335 /* Mark method in class */
336 CLASSNAME1(class," MARKSUBS ");
337 METHINFOt(topmethod," TOP ");
338 rtaMarkMethod(class, topmethod);
340 /* Mark method in subclasses */
341 if (class->sub != NULL) {
344 if (!(topmethod->flags & ACC_FINAL )) {
345 for (subs = class->sub;subs != NULL;subs = subs->nextsub) {
346 CLASSNAME1(subs," SUBS ");
347 rtaMarkSubs(subs, topmethod);
355 /*********************************************************************/
357 void rtaMarkInterfaceSubs(methodinfo *mi) {
359 if (mi->class->classUsed == NOTUSED) {
360 mi->class->classUsed = USED;
361 class_java_lang_Object->impldBy = addElement(class_java_lang_Object -> impldBy, mi->class);
364 /* add interface class to list kept in Object */
365 mi->methodUsed = USED;
368 subs = mi->class->impldBy;
369 /*RTAPRINT08invokeInterface1*/
370 while (subs != NULL) {
371 classinfo * isubs = subs->classType;
372 /*RTAPRINT09invokeInterface2*/
373 /* Mark method (mark/used) in classes that implement the method */
374 if (isubs->classUsed != NOTUSED) {
377 submeth = class_findmethod(isubs,mi->name, mi->descriptor);
379 submeth->monoPoly = POLY; /* poly even if nosubs */
380 rtaMarkSubs(isubs, mi);
383 subs = subs->nextClass;
388 /*********************************************************************/
390 int parseRT(methodinfo *m)
392 int p; /* java instruction counter */
393 int nextp; /* start of next java instruction */
394 int opcode; /* java opcode */
395 int i; /* temp for different uses (counters)*/
396 bool iswide = false; /* true if last instruction was a wide*/
399 METHINFOt(m,"\n----RT PARSING:");
400 if (DEBUGr) printf("\n");
402 /* scan all java instructions */
403 for (p = 0; p < m->jcodelength; p = nextp) {
405 opcode = code_get_u1(p,m); /* fetch op code */
408 nextp = p + jcommandsize[opcode]; /* compute next instrtart */
409 if (nextp > m->jcodelength)
410 panic("Unexpected end of bytecode");
442 /* wider index for loading, storing and incrementing */
456 case JAVA_LOOKUPSWITCH:
459 nextp = ALIGN((p + 1), 4) + 4;
460 num = code_get_u4(nextp,m);
461 nextp += (code_get_u4(nextp,m)) * 8 + 4;
466 case JAVA_TABLESWITCH:
469 nextp = ALIGN ((p + 1),4);
470 num = code_get_s4(nextp + 4, m);
471 num = code_get_s4(nextp + 8, m) - num;
472 nextp = nextp + 16 + 4 * num;
475 /*********************/
479 i = code_get_u2(p + 1,m);
484 fr = class_getconstant(m->class, i, CONSTANT_Fieldref);
485 LAZYLOADING(fr->class)
487 fi = class_resolvefield(fr->class,
494 return 0; /* was NULL */
496 CLASSNAME(fi->class,"\tPUTSTATIC: ");
497 if (!fi->class->initialized) {
498 m->isleafmethod = false;
500 addClassInit( fi->class,
505 case JAVA_INVOKESTATIC:
506 case JAVA_INVOKESPECIAL:
507 i = code_get_u2(p + 1,m);
512 m->isleafmethod = false;
513 mr = class_getconstant(m->class, i, CONSTANT_Methodref);
514 LAZYLOADING(mr->class)
515 mi = class_resolveclassmethod(mr->class,
525 if ((opcode == JAVA_INVOKESTATIC)
526 || (mi->flags & ACC_STATIC)
527 || (mi->flags & ACC_PRIVATE)
528 || (mi->flags & ACC_FINAL) )
530 if (mi->class->classUsed == NOTUSED){
531 addClassInit( mi->class,
533 if (mi->class->classUsed == NOTUSED){
534 mi->class->classUsed = PARTUSED; }
536 if (mi->class->classUsed == NOTUSED) {
537 METHINFOt(mi,"WAS / WARUM 1")
538 panic("WAS /WARUM 1 ????");
540 if (opcode == JAVA_INVOKESTATIC)
542 "addTo INVOKESTATIC ");
545 "addTo INVOKESPECIAL ");
548 /* Handle special <init> calls */
550 /* for now same as rest */
551 if (mi->class->classUsed == NOTUSED){
553 call of super's <init> then
554 methods of super class not all used */
555 if (utf_new_char("<init>")==mi->name) {
556 if (m->class->super == mi->class) {
558 addClassInit(mi->class,
560 if (mi->class->classUsed == NOTUSED) mi->class->classUsed = PARTUSED;
563 addClassInit(mi->class,
567 if (utf_new_char("<clinit>")==mi->name)
568 addClassInit( mi->class,
571 if (!((utf_new_char("<init>")==mi->name))
572 || (utf_new_char("<clinit>")==mi->name)) {
573 METHINFOt(mi,"SPECIAL not init:")
574 addClassInit( mi->class,
579 if (utf_new_char("<init>")==mi->name) {
580 if (mi->class->classUsed == NOTUSED) {
581 METHINFOt(mi,"WAS / WARUM 2")
582 panic("WAS /WARUM 2 ????");
585 "addTo INVOKESPECIAL ");
589 /*** assume if method can't be resolved won't actually be called or
590 there is a real error in classpath and in normal parse an exception
591 will be thrown. Following debug print can verify this
593 CLASSNAME1(mr->class,"CouldNOT Resolve method:");printf(".");fflush(stdout);
594 utf_display(mr->name); printf(" "); fflush(stdout);
595 utf_display(mr->descriptor); printf("\n");fflush(stdout);
600 case JAVA_INVOKEVIRTUAL:
601 i = code_get_u2(p + 1,m);
606 m->isleafmethod = false;
607 mr = m->class->cpinfos[i];
608 /*mr = class_getconstant(m->class, i, CONSTANT_Methodref)*/
609 LAZYLOADING(mr->class)
610 mi = class_resolveclassmethod(mr->class,
619 METHINFOt(mi,"INVOKEVIRTUAL ::");
620 if ((mi->flags & ACC_STATIC)
621 || (mi->flags & ACC_PRIVATE)
622 || (mi->flags & ACC_FINAL) )
624 if (mi->class->classUsed == NOTUSED){
625 addClassInit(mi->class,
630 "addTo INVOKEVIRTUAL ");
634 rtaMarkSubs(mi->class,mi);
638 CLASSNAME1(mr->class,"CouldNOT Resolve virt meth:");printf(".");fflush(stdout);
639 utf_display(mr->name); printf(" "); fflush(stdout);
640 utf_display(mr->descriptor); printf("\n");fflush(stdout);
645 case JAVA_INVOKEINTERFACE:
646 i = code_get_u2(p + 1,m);
651 m->isleafmethod = false;
653 mr = class_getconstant(m->class, i, CONSTANT_InterfaceMethodref);
654 LAZYLOADING(mr->class)
656 mi = class_resolveinterfacemethod(mr->class,
663 METHINFOt(mi,"\tINVOKEINTERFACE: ")
664 rtaMarkInterfaceSubs(mi);
666 /* see INVOKESTATIC for explanation about */
667 /* case when Interface is not resolved */
668 /* descriptor2types(mi); ?? do need paramcnt? */
673 /* means class is at least passed as a parameter */
674 /* class is really instantiated when class.<init> called*/
675 i = code_get_u2(p + 1,m);
678 ci = class_getconstant(m->class, i, CONSTANT_Class);
679 m->isleafmethod = false; /* why for new ? */
680 /* s_count++; look for s_counts for VTA */
681 /* ci->classUsed=USED; */
682 /* add marked methods */
683 CLASSNAME(ci,"NEW : do nothing");
688 case JAVA_INSTANCEOF:
690 i = code_get_u2(p + 1,m);
694 class_getconstant(m->class, i, CONSTANT_Class);
697 if (cls->classUsed == NOTUSED){
714 /* Helper fn for initialize **********************************************/
716 int getline(char *line, int max, FILE *inFP) {
717 if (fgets(line, max, inFP) == NULL)
720 return strlen((const char *) line);
723 /* Initialize RTA Work list ***********************************************/
725 /*-- Get meth ptr for class.meth desc and add to RTA worklist --*/
726 #define SYSADD(cls,meth,desc,txt) \
727 c = class_new(utf_new_char(cls)); \
729 callmeth = class_resolveclassmethod(c, \
730 utf_new_char(meth), \
731 utf_new_char(desc), \
734 if (callmeth->class->classUsed != USED) { \
735 c->classUsed = PARTUSED; \
736 addClassInit(callmeth->class, \
739 callmeth->monoPoly = POLY; \
740 addToRtaWorkList(callmeth,txt);
744 Initialize RTA work list with methods/classes from:
747 rtMissedIn list (missed becaused called from NATIVE &/or dynamic calls
749 methodinfo *initializeRTAworklist(methodinfo *m) {
751 methodinfo* callmeth;
752 char systxt[] = "System Call :";
753 char missedtxt[] = "rtMissedIn Call :";
755 FILE *rtMissedIn; /* Methods missed during previous RTA parse */
757 char* class, *meth, *desc;
758 /*char filename[256] = "rtMissed"*/
759 char filenameIn[256] = "rtIn/";
760 methodinfo *rm =NULL; /* return methodinfo ptr to main method */
763 /* Create RTA call work list */
764 rtaWorkList = NEW(list);
765 list_init(rtaWorkList, OFFSET(rtaNode,linkage) );
767 /* Add first method to call list */
768 m->class->classUsed = USED;
769 addToRtaWorkList(m,systxt);
771 /* Add system called methods */
772 SYSADD(mainstring, "main","([Ljava/lang/String;)V",systxt)
774 SYSADD("java/lang/Runtime","getRuntime","()Ljava/lang/Runtime;",systxt)
775 SYSADD("java/lang/Runtime","exit","(I)V",systxt)
777 /*----- rtMissedIn 0 */
778 if ( (rtMissedIn = fopen("rtMissedIn0", "r")) == NULL) {
780 {printf("No rtMissedIn0 file\n");fflush(stdout);}
783 while (getline(line,256,rtMissedIn)) {
784 class = strtok(line, " \n");
785 meth = strtok(NULL, " \n");
786 desc = strtok(NULL, " \n");
787 SYSADD(class,meth,desc,missedtxt)
791 /*----- rtMissedIn pgm specific */
792 printf("filenameIn=%s|mainstring=%s\n",filenameIn,mainstring); fflush(stdout);
793 strcat(filenameIn, (const char *)mainstring);
794 printf("filenameIn=%s|\n",filenameIn); fflush(stdout);
795 if ( (rtMissedIn = fopen(filenameIn, "r")) == NULL) {
797 {printf("NNo rtMissedIn=%s file\n",filenameIn);fflush(stdout);}
800 while (getline(line,256,rtMissedIn)) {
801 class = strtok(line, " \n");
802 meth = strtok(NULL, " \n");
803 desc = strtok(NULL, " \n");
804 if ((class == NULL) || (meth == NULL) || (desc == NULL)) {
805 fprintf(stderr,"Error in rtMissedIn file for: %s.%s %s\n",class, meth, desc);
807 panic ("Error in rtMissedIn file for: class.meth, desc\n");
809 SYSADD(class,meth,desc,missedtxt)
815 /*- end initializeRTAworklist-------- */
819 /*-- RTA -- *******************************************************/
820 int RT_jit_parse(methodinfo *m)
822 methodinfo *rt_method;
824 methodinfo *mainmeth;
826 /* Should only be called once */
828 firstCall = false; /* turn flag off */
830 /*----- RTA initializations --------*/
832 log_text("RTA static analysis started.\n");
834 mainmeth = initializeRTAworklist(m);
836 if ( (rtMissed = fopen("rtMissed", "w")) == NULL) {
837 printf("CACAO - rtMissed file: cant open file to write\n");
839 /* Note: rtMissed must be renamed to rtMissedIn to be used as input */
841 /*------ process RTA call work list --------*/
842 for (rta =list_first(rtaWorkList);
844 rta =list_next(rtaWorkList,rta))
846 rt_method = rta->method;
847 if (! ( (rt_method->flags & ACC_NATIVE )
848 || (rt_method->flags & ACC_ABSTRACT) ) )
850 /* RTA parse to approxmate....
851 what classes/methods will really be used during execution */
855 if (rt_method->flags & ACC_NATIVE )
857 METHINFOt(rt_method,"TO BE NATIVE RTA PARSED :")
858 /* parseRTpseudo(rt_method); */
861 printf("Abstract method in RTA Work List: ");
863 panic("Abstract method in RTA Work List.");
870 printRThierarchyInfo(m);
872 printCallgraph(rtaWorkList);
876 log_text("RTA static analysis done.\n");
883 * These are local overrides for various environment variables in Emacs.
884 * Please do not remove this and leave it at the end of the file, where
885 * Emacs will automagically detect them.
886 * ---------------------------------------------------------------------
889 * indent-tabs-mode: t