001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.adaptive.util;
014    
015    import java.io.BufferedReader;
016    import java.io.FileInputStream;
017    import java.io.IOException;
018    import java.io.InputStreamReader;
019    import java.util.StringTokenizer;
020    import org.jikesrvm.VM;
021    import org.jikesrvm.adaptive.controller.Controller;
022    import org.jikesrvm.adaptive.database.callgraph.PartialCallGraph;
023    import org.jikesrvm.classloader.RVMClassLoader;
024    import org.jikesrvm.classloader.MemberReference;
025    import org.jikesrvm.classloader.RVMMethod;
026    import org.jikesrvm.classloader.MethodReference;
027    
028    /**
029     * Utility to read dynamic call graph annotations from file in ASCII format.
030     * Takes a single argument: the name of the file containing the ASCII
031     * annotations.  Each line of the file corresponds to an annotation
032     * for one method and has the following format:
033     * <p>
034     * <pre>
035     * CallSite &lt; classloader, classname, method, signature&gt; method_size byte_code_index &lt;callee_classloader, classname, method, signature&gt; method_size weight: weight
036     * </pre>
037     * Where the types and meanings of the fields is as follows:
038     * <ul>
039     * <li><code>&lt;signature></code> <i>string</i> The method signature</li>
040     * </ul>
041     *
042     *
043     * @see CompilerAdvice
044     */
045    public class DynamicCallFileInfoReader {
046    
047      /**
048       * Read annotations from a specified file. Reads all annotations at
049       * once and returns a collection of compiler advice attributes.
050       *
051       * @param file The annotation file to be read
052       */
053      public static void readDynamicCallFile(String file, boolean boot) {
054        BufferedReader fileIn = null;
055    
056        if (file == null) return;// null;
057    
058        if ((!VM.runningVM) && (Controller.dcg == null)) {
059          Controller.dcg = new PartialCallGraph(300);
060        } else if (Controller.dcg == null) {
061          System.out.println("dcg is null ");
062          return;
063        } else {
064          Controller.dcg.reset();  // clear any values accumulated to this point
065        }
066        try {
067          fileIn = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
068          try {
069            for (String s = fileIn.readLine(); s != null; s = fileIn.readLine()) {
070              if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
071                VM.sysWriteln(s);
072              } else if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
073                VM.sysWrite(".");
074              }
075              s = s.replaceAll("\\{urls[^\\}]*\\}", ""); // strip classloader cruft we can't parse
076              StringTokenizer parser = new StringTokenizer(s, " \n,");
077              readOneCallSiteAttribute(parser, boot);
078            }
079          } catch (IOException e) {
080            e.printStackTrace();
081            VM.sysFail("Error parsing input dynamic call graph file" + file);
082          }
083          fileIn.close();
084        } catch (java.io.FileNotFoundException e) {
085          System.out.println("IO: Couldn't read compiler advice attribute file: " + file + e);
086        } catch (java.io.UnsupportedEncodingException e) {
087          System.out.println("IO: UTF-16 is not supported: " + e);
088        } catch (IOException e) {
089          VM.sysFail("Error closing input dynamic call graph file" + file);
090        }
091      }
092    
093      private static void readOneCallSiteAttribute(StringTokenizer parser, boolean boot) {
094        String firstToken = parser.nextToken();
095        if (firstToken.equals("CallSite")) {
096          try {
097            MemberReference callerKey = MemberReference.parse(parser, boot);
098            if (callerKey == null) return;
099            MethodReference callerRef = callerKey.asMethodReference();
100            RVMMethod caller, callee;
101            caller = getMethod(callerRef);
102    
103            @SuppressWarnings("unused") // serves as doco - token skipped
104            int callerSize = Integer.parseInt(parser.nextToken());
105            int bci = Integer.parseInt(parser.nextToken());
106            MemberReference calleeKey = MemberReference.parse(parser, boot);
107            if (calleeKey == null) return;
108            MethodReference calleeRef = calleeKey.asMethodReference();
109            callee = getMethod(calleeRef);
110    
111            @SuppressWarnings("unused") // serves as doco - token skipped
112            int calleeSize = Integer.parseInt(parser.nextToken());
113            parser.nextToken(); // skip "weight:"
114            float weight = Float.parseFloat(parser.nextToken());
115            if ((caller == null) || (callee == null)) {
116              Controller.dcg.incrementUnResolvedEdge(callerRef, bci, calleeRef, weight);
117            } else {
118              Controller.dcg.incrementEdge(caller, bci, callee, weight);
119            }
120          } catch (Exception e) {
121            VM.sysWriteln("Caught exception: "+e);
122          }
123        } else {
124          VM.sysFail("Format error in dynamic call graph file");
125        }
126      }
127    
128      /**
129       * Establish the RVMMethod for a given MethodReference gracefully.
130       *
131       * @param ref The MethodReference
132       * @return The RVMMethod, or {@code null} on failure.
133       */
134      private static RVMMethod getMethod(MethodReference ref) {
135        if (ref.getType().getClassLoader() == RVMClassLoader.getApplicationClassLoader()) {
136          try {
137            return ref.resolve();
138          } catch (NoClassDefFoundError e) {
139            if (Controller.options.BULK_COMPILATION_VERBOSITY >= 1)
140              VM.sysWriteln("Warning: could not define class: " + ref.getType());
141            return null;
142          } catch (NoSuchMethodError e) {
143            if (Controller.options.BULK_COMPILATION_VERBOSITY >= 1)
144              VM.sysWriteln("Warning: could not load method: " + ref);
145            return null;
146          }
147        } else {
148          return ref.getResolvedMember();
149        }
150      }
151    }
152    
153    
154    
155    
156