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 1419 2004-10-21 09:59:33Z carolyn $
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"
77 static bool firstCall= true;
78 static list *rtaWorkList;
79 FILE *rtMissed; /* Methods missed during RTA parse of Main */
81 #define LAZYLOADING(class) { \
82 if (!class_load(class)) \
84 if (!class_link(class)) \
88 bool DEBUGopcodes = false;
90 #define METHINFO(mm) \
91 if (DEBUGr == true) { \
92 printf("<c%i/m%i>\t",mm->class->classUsed,mm->methodUsed); \
93 utf_display(mm->class->name); printf("."); fflush(stdout); \
94 method_display(mm); fflush(stdout); }
96 #define METHINFOt(mm,TXT) \
97 if (DEBUGr == true) { \
99 printf("<c%i/m%i>\t",mm->class->classUsed,mm->methodUsed); \
100 utf_display(mm->class->name); printf("."); fflush(stdout); \
101 method_display(mm); fflush(stdout); }
103 #define CLASSNAME1(cls,TXT) \
104 if (DEBUGr == true) {printf(TXT); \
105 printf("<c%i>\t",cls->classUsed); \
106 utf_display(cls->name); fflush(stdout);}
108 #define CLASSNAMEop(cls) \
109 if (DEBUGr == true) {printf("\t%s: ",opcode_names[opcode]);\
110 printf("<c%i>\t",cls->classUsed); \
111 utf_display(cls->name); printf("\n");fflush(stdout);}
113 #define CLASSNAME(cls,TXT) \
114 if (DEBUGr == true) { printf(TXT); \
115 printf("<c%i>\t",cls->classUsed); \
116 utf_display(cls->name); printf("\n");fflush(stdout);}
119 if (DEBUGopcodes == true) {printf("Parse p=%i<%i< opcode=<%i> %s\n", \
120 p, m->jcodelength,opcode,opcode_names[opcode]);}
122 /*********************************************************************/
124 void addToRtaWorkList(methodinfo *meth, char *info) {
127 if (meth->methodUsed == USED) return;
129 if (!(meth->flags & ACC_ABSTRACT)) {
130 count_methods_marked_used++;
132 meth ->methodUsed = USED;
135 list_addlast(rtaWorkList,rta);
139 printf("Method not added to work list!!!<%i> : ",
140 meth->methodUsed); fflush(stdout);
146 /**************************************************************************/
147 /* Add Marked methods for input class ci */
148 /* Add methods with the same name and descriptor as implemented interfaces*/
149 /* with the same method name */
151 /*------------------------------------------------------------------------*/
152 void rtaAddMarkedMethods(classinfo *ci) {
155 /* add marked methods to callgraph */
156 for (ii=0; ii<ci->methodscount; ii++) {
157 methodinfo *mi = &(ci->methods[ii]);
159 if (mi->methodUsed == MARKED) {
161 "addTo was MARKED:");
164 for (jj=0; jj < ci -> interfacescount; jj++) {
165 classinfo *ici = ci -> interfaces [jj];
166 /* use resolve method....!!!! */
167 if (ici -> classUsed != NOTUSED) {
168 for (mm=0; mm< ici->methodscount; mm++) {
169 methodinfo *imi = &(ici->methods[mm]);
170 /*if interface method=method is used*/
171 if ( (imi->methodUsed == USED)
172 && ( (imi->name == mi->name)
173 && (imi->descriptor == mi->descriptor))) {
175 "addTo was interfaced used/MARKED:");
185 /*********************************************************************/
186 void addClassInit(classinfo *ci, bool clinits, bool finalizes, bool addmark)
191 ci->classUsed = USED;
193 if (clinits) { /* No <clinit> available - ignore */
194 mi = class_findmethod(ci,
195 utf_new_char("<clinit>"),
196 utf_new_char("()V"));
198 if (ci->classUsed != USED)
199 ci->classUsed = PARTUSED;
200 addToRtaWorkList(mi,"addTo CLINIT added:");
204 /*Special Case for System class init:
205 add java/lang/initializeSystemClass to callgraph */
206 if (ci->name == utf_new_char("initializeSystemClass")) {
207 /* ?? what is name of method ?? */
211 mi = class_findmethod(ci,
212 utf_new_char("finalize"),
213 utf_new_char("()V"));
215 if (ci->classUsed != USED)
216 ci->classUsed = PARTUSED;
217 addToRtaWorkList(mi,"addTo FINALIZE added:");
222 /* rtaAddMarkedMethods(ci); */
228 /*--------------------------------------------------------------*/
229 /* Mark the method with same name /descriptor in topmethod */
232 /* Class marked USED and method defined in this class -> */
233 /* -> mark method as USED */
234 /* Class not marked USED and method defined in this class -> */
235 /* -> if Method NOTUSED mark method as MARKED */
237 /* Class USED, but method not defined in this class -> */
238 /* -> 1) search up the heirarchy and mark method where defined */
239 /* 2) if class where method is defined is not USED -> */
240 /* -> mark class with defined method as PARTUSED */
241 /*--------------------------------------------------------------*/
243 void rtaMarkMethod(classinfo *class, methodinfo *topmethod) {
245 utf *name = topmethod->name;
246 utf *descriptor = topmethod->descriptor;
249 /* See if method defined in class heirarchy */
250 submeth = class_resolvemethod(class, name, descriptor);
252 panic("parse RT: Method not found in class hierarchy");
253 if (submeth->methodUsed == USED) return;
257 /* Class Type Analysis if class.method in virt cone marks it used */
258 /* very inexact, too many extra methods */
259 addClassInit( submeth->class,
261 addToRtaWorkList(submeth,
262 "addTo RTA VIRT CONE:");
266 if (submeth->class == class) {
268 /*--- Method defined in class -----------------------------*/
269 if ( submeth->class->classUsed == USED) {
270 /* method defined in this class -> */
271 /* Class IS marked USED */
272 /* -> mark method as USED */
273 addToRtaWorkList(submeth,
274 "addTo VIRT CONE 1:");
277 /* method defined in this class -> */
278 /* Class IS NOT marked USED (PART or NOTUSED) */
279 /* -> if Method NOTUSED mark method as MARKED */
281 "\tmarked VIRT CONE 2:");
282 submeth->methodUsed = MARKED;
283 /* Note: if class NOTUSED and subclass is used handled */
284 /* by subsequent calls to rtaMarkMethods for cone */
286 } /* end defined in class */
289 /*--- Method NOT defined in class ---------------*/
290 /* first mark classes if needed */
291 if (submeth->class->classUsed == NOTUSED) {
292 submeth->class->classUsed = PARTUSED;
293 if (class->classUsed != USED) {
294 submeth->methodUsed = MARKED;
295 METHINFOt(submeth,"JUST MARKED :");
298 /* add method to rta work list if conditions met */
299 //if ( (submeth->class->classUsed == USED) ||
300 if (class->classUsed == USED) {
301 addToRtaWorkList(submeth,
302 "addTo VIRT CONE 3:");
304 } /* end NOT defined in class */
308 /*----------------------------------------------------------------------*/
309 /* Mark the method with the same name and descriptor as topmethod */
310 /* and any subclass where the method is defined and/or class is used */
312 /*----------------------------------------------------------------------*/
313 void rtaMarkSubs(classinfo *class, methodinfo *topmethod) {
315 /* Mark method in class */
316 CLASSNAME1(class," MARKSUBS ");
317 METHINFOt(topmethod," TOP ");
318 rtaMarkMethod(class, topmethod);
320 /* Mark method in subclasses */
321 if (class->sub != NULL) {
324 if (!(topmethod->flags & ACC_FINAL )) {
325 for (subs = class->sub;subs != NULL;subs = subs->nextsub) {
326 CLASSNAME1(subs," SUBS ");
327 rtaMarkSubs(subs, topmethod);
335 /*********************************************************************/
337 void rtaMarkInterfaceSubs(methodinfo *mi) {
339 if (mi->class->classUsed == NOTUSED) {
340 mi->class->classUsed = USED;
341 class_java_lang_Object->impldBy = addElement(class_java_lang_Object -> impldBy, mi->class);
344 /* add interface class to list kept in Object */
345 mi->methodUsed = USED;
348 subs = mi->class->impldBy;
349 /*RTAPRINT08invokeInterface1*/
350 while (subs != NULL) {
351 classinfo * isubs = subs->classType;
352 /*RTAPRINT09invokeInterface2*/
353 /* Mark method (mark/used) in classes that implement the method */
354 if (isubs->classUsed != NOTUSED) {
357 submeth = class_findmethod(isubs,mi->name, mi->descriptor);
359 submeth->monoPoly = POLY; /* poly even if nosubs */
360 rtaMarkSubs(isubs, mi);
363 subs = subs->nextClass;
368 /*********************************************************************/
370 int parseRT(methodinfo *m)
372 int p; /* java instruction counter */
373 int nextp; /* start of next java instruction */
374 int opcode; /* java opcode */
375 int i; /* temp for different uses (counters)*/
376 bool iswide = false; /* true if last instruction was a wide*/
379 METHINFOt(m,"\n----RT PARSING:");
380 if (DEBUGr) printf("\n");
382 /* scan all java instructions */
383 for (p = 0; p < m->jcodelength; p = nextp) {
385 opcode = code_get_u1(p,m); /* fetch op code */
388 nextp = p + jcommandsize[opcode]; /* compute next instrtart */
389 if (nextp > m->jcodelength)
390 panic("Unexpected end of bytecode");
422 /* wider index for loading, storing and incrementing */
436 case JAVA_LOOKUPSWITCH:
439 nextp = ALIGN((p + 1), 4) + 4;
440 num = code_get_u4(nextp,m);
441 nextp += (code_get_u4(nextp,m)) * 8 + 4;
446 case JAVA_TABLESWITCH:
449 nextp = ALIGN ((p + 1),4);
450 num = code_get_s4(nextp + 4, m);
451 num = code_get_s4(nextp + 8, m) - num;
452 nextp = nextp + 16 + 4 * num;
455 /*********************/
459 i = code_get_u2(p + 1,m);
464 fr = class_getconstant(m->class, i, CONSTANT_Fieldref);
465 LAZYLOADING(fr->class)
467 fi = class_resolvefield(fr->class,
474 return 0; // was NULL
476 CLASSNAME(fi->class,"\tPUTSTATIC: ");
477 if (!fi->class->initialized) {
478 m->isleafmethod = false;
480 addClassInit( fi->class,
485 case JAVA_INVOKESTATIC:
486 case JAVA_INVOKESPECIAL:
487 i = code_get_u2(p + 1,m);
492 m->isleafmethod = false;
493 mr = class_getconstant(m->class, i, CONSTANT_Methodref);
494 LAZYLOADING(mr->class)
495 mi = class_resolveclassmethod(mr->class,
504 if ((opcode == JAVA_INVOKESTATIC)
505 || (mi->flags & ACC_STATIC)
506 || (mi->flags & ACC_PRIVATE)
507 || (mi->flags & ACC_FINAL) )
509 if (mi->class->classUsed == NOTUSED){
510 addClassInit( mi->class,
513 if (opcode == JAVA_INVOKESTATIC)
515 "addTo INVOKESTATIC ");
518 "addTo INVOKESPECIAL ");
521 /* Handle special <init> calls */
523 call of super's <init> then
524 methods of super class not all used */
526 /* for now same as rest */
527 if (mi->class->classUsed == NOTUSED){
528 if (utf_new_char("<init>")==mi->name)
529 addClassInit( mi->class,
531 if (utf_new_char("<clinit>")==mi->name)
532 addClassInit( mi->class,
534 if (!((utf_new_char("<init>")==mi->name))
535 || (utf_new_char("<clinit>")==mi->name))
536 METHINFOt(mi,"SPECIAL not init:")
537 addClassInit( mi->class,
543 "addTo INVOKESPECIALi ");
546 /*** assume if method can't be resolved won't actually be called or
547 there is a real error in classpath and in normal parse an exception
548 will be thrown. Following debug print can verify this
550 CLASSNAME1(mr->class,"CouldNOT Resolve method:");printf(".");fflush(stdout);
551 utf_display(mr->name); printf(" "); fflush(stdout);
552 utf_display(mr->descriptor); printf("\n");fflush(stdout);
557 case JAVA_INVOKEVIRTUAL:
558 i = code_get_u2(p + 1,m);
563 m->isleafmethod = false;
564 mr = m->class->cpinfos[i];
565 /*mr = class_getconstant(m->class, i, CONSTANT_Methodref)*/
566 LAZYLOADING(mr->class)
567 mi = class_resolveclassmethod(mr->class,
576 METHINFOt(mi,"INVOKEVIRTUAL ::");
577 if ((mi->flags & ACC_STATIC)
578 || (mi->flags & ACC_PRIVATE)
579 || (mi->flags & ACC_FINAL) )
581 if (mi->class->classUsed == NOTUSED){
582 addClassInit(mi->class,
586 "addTo INVOKEVIRTUAL ");
590 rtaMarkSubs(mi->class,mi);
594 CLASSNAME1(mr->class,"CouldNOT Resolve virt meth:");printf(".");fflush(stdout);
595 utf_display(mr->name); printf(" "); fflush(stdout);
596 utf_display(mr->descriptor); printf("\n");fflush(stdout);
601 case JAVA_INVOKEINTERFACE:
602 i = code_get_u2(p + 1,m);
607 m->isleafmethod = false;
609 mr = class_getconstant(m->class, i, CONSTANT_InterfaceMethodref);
610 LAZYLOADING(mr->class)
612 mi = class_resolveinterfacemethod(mr->class,
619 METHINFOt(mi,"\tINVOKEINTERFACE: ")
620 rtaMarkInterfaceSubs(mi);
622 /* see INVOKESTATIC for explanation about */
623 /* case when Interface is not resolved */
624 //descriptor2types(mi); ?? do need paramcnt?
629 /* means class is at least passed as a parameter */
630 /* class is really instantiated when class.<init> called*/
631 i = code_get_u2(p + 1,m);
634 ci = class_getconstant(m->class, i, CONSTANT_Class);
635 m->isleafmethod = false; /* why for new ? */
636 // s_count++; look for s_counts for VTA
637 //ci->classUsed=USED;
638 /* add marked methods */
639 CLASSNAME(ci,"NEW : do nothing");
644 case JAVA_INSTANCEOF:
646 i = code_get_u2(p + 1,m);
650 class_getconstant(m->class, i, CONSTANT_Class);
666 /* Helper fn for initialize **********************************************/
668 int getline(char *line, int max, FILE *inFP) {
669 if (fgets(line, max, inFP) == NULL)
672 return strlen((const char *) line);
675 /* Initialize RTA Work list ***********************************************/
677 /*-- Get meth ptr for class.meth desc and add to RTA worklist --*/
678 #define SYSADD(cls,meth,desc,txt) \
679 c = class_new(utf_new_char(cls)); \
681 callmeth = class_resolveclassmethod(c, \
682 utf_new_char(meth), \
683 utf_new_char(desc), \
686 if (callmeth->class->classUsed != USED) { \
687 addClassInit(callmeth->class, \
690 addToRtaWorkList(callmeth,txt);
694 Initialize RTA work list with methods/classes from:
697 rtMissedIn list (missed becaused called from NATIVE &/or dynamic calls
699 int initializeRTAworklist(methodinfo *m) {
701 methodinfo* callmeth;
702 char systxt[] = "System Call :";
703 char missedtxt[] = "rtMissedIn Call :";
705 FILE *rtMissedIn; /* Methods missed during previous RTA parse */
707 char* class, *meth, *desc;
708 char filename[256] = "rtMissed";
710 /* Create RTA call work list */
711 rtaWorkList = NEW(list);
712 list_init(rtaWorkList, OFFSET(rtaNode,linkage) );
714 /* Add first method to call list */
715 m->class->classUsed = USED;
716 addToRtaWorkList(m,systxt);
718 /* Add system called methods */
719 SYSADD(mainstring, "main","([Ljava/lang/String;)V",systxt)
720 SYSADD("java/lang/Runtime","getRuntime","()Ljava/lang/Runtime;",systxt)
721 SYSADD("java/lang/Runtime","exit","(I)V",systxt)
723 /*----- rtMissedIn 0 */
724 if ( (rtMissedIn = fopen("rtMissedIn0", "r")) == NULL) {
726 {printf("No rtMissedIn0 file\n");fflush(stdout);}
729 while (getline(line,256,rtMissedIn)) {
730 class = strtok(line, " \n");
731 meth = strtok(NULL, " \n");
732 desc = strtok(NULL, " \n");
733 SYSADD(class,meth,desc,missedtxt)
737 /*----- rtMissedIn pgm specific */
738 strcat(filename, (const char *)mainstring);
739 if ( (rtMissedIn = fopen(filename, "r")) == NULL) {
741 {printf("No rtMissedIn=%s file\n",filename);fflush(stdout);}
744 while (getline(line,256,rtMissedIn)) {
745 class = strtok(line, " \n");
746 meth = strtok(NULL, " \n");
747 desc = strtok(NULL, " \n");
748 SYSADD(class,meth,desc,missedtxt)
753 /*- end initializeRTAworklist-------- */
757 /*-- RTA -- *******************************************************/
758 int RT_jit_parse(methodinfo *m)
760 methodinfo *rt_method;
763 /* Should only be called once */
765 firstCall = false; /* turn flag off */
767 /*----- RTA initializations --------*/
769 log_text("RTA static analysis started.\n");
771 initializeRTAworklist(m);
773 if ( (rtMissed = fopen("rtMissed", "w")) == NULL) {
774 printf("CACAO - rtMissed file: cant open file to write\n");
776 /* Note: rtMissed must be renamed to rtMissedIn to be used as input */
778 /*------ process RTA call work list --------*/
779 for (rta =list_first(rtaWorkList);
781 rta =list_next(rtaWorkList,rta))
783 rt_method = rta->method;
784 if (! ( (rt_method->flags & ACC_NATIVE )
785 || (rt_method->flags & ACC_ABSTRACT) ) )
787 /* RTA parse to approxmate....
788 what classes/methods will really be used during execution */
792 if (rt_method->flags & ACC_NATIVE )
794 METHINFOt(rt_method,"TO BE NATIVE RTA PARSED :")
795 /* parseRTpseudo(rt_method); */
798 printf("Abstract method in RTA Work List: ");
800 panic("Abstract method in RTA Work List.");
806 log_text("RTA static analysis done.\n");
813 * These are local overrides for various environment variables in Emacs.
814 * Please do not remove this and leave it at the end of the file, where
815 * Emacs will automagically detect them.
816 * ---------------------------------------------------------------------
819 * indent-tabs-mode: t