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 */
013package org.jikesrvm.adaptive.util;
014
015import java.io.BufferedReader;
016import java.io.FileInputStream;
017import java.io.IOException;
018import java.io.InputStreamReader;
019import java.util.StringTokenizer;
020import org.jikesrvm.VM;
021import org.jikesrvm.adaptive.controller.Controller;
022import org.jikesrvm.adaptive.database.callgraph.PartialCallGraph;
023import org.jikesrvm.classloader.RVMClassLoader;
024import org.jikesrvm.classloader.MemberReference;
025import org.jikesrvm.classloader.RVMMethod;
026import 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 * <pre>
034 * CallSite &lt; classloader, classname, method, signature&gt; method_size byte_code_index &lt;callee_classloader, classname, method, signature&gt; method_size weight: weight
035 * </pre>
036 * Where the types and meanings of the fields is as follows:
037 * <ul>
038 * <li><code>&lt;signature&gt;</code> <i>string</i> The method signature</li>
039 * </ul>
040 *
041 *
042 * @see CompilerAdvice
043 */
044public class DynamicCallFileInfoReader {
045
046  public static void readDynamicCallFile(String file, boolean boot) {
047    BufferedReader fileIn = null;
048
049    if (file == null) return;// null;
050
051    if ((!VM.runningVM) && (Controller.dcg == null)) {
052      Controller.dcg = new PartialCallGraph(300);
053    } else if (Controller.dcg == null) {
054      System.out.println("dcg is null ");
055      return;
056    } else {
057      Controller.dcg.reset();  // clear any values accumulated to this point
058    }
059    try {
060      fileIn = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
061      try {
062        for (String s = fileIn.readLine(); s != null; s = fileIn.readLine()) {
063          if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
064            VM.sysWriteln(s);
065          } else if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
066            VM.sysWrite(".");
067          }
068          s = s.replaceAll("\\{urls[^\\}]*\\}", ""); // strip classloader cruft we can't parse
069          StringTokenizer parser = new StringTokenizer(s, " \n,");
070          readOneCallSiteAttribute(parser, boot);
071        }
072      } catch (IOException e) {
073        e.printStackTrace();
074        VM.sysFail("Error parsing input dynamic call graph file" + file);
075      }
076      fileIn.close();
077    } catch (java.io.FileNotFoundException e) {
078      System.out.println("IO: Couldn't read compiler advice attribute file: " + file + e);
079    } catch (java.io.UnsupportedEncodingException e) {
080      System.out.println("IO: UTF-16 is not supported: " + e);
081    } catch (IOException e) {
082      VM.sysFail("Error closing input dynamic call graph file" + file);
083    }
084  }
085
086  private static void readOneCallSiteAttribute(StringTokenizer parser, boolean boot) {
087    String firstToken = parser.nextToken();
088    if (firstToken.equals("CallSite")) {
089      try {
090        MemberReference callerKey = MemberReference.parse(parser, boot);
091        if (callerKey == null) return;
092        MethodReference callerRef = callerKey.asMethodReference();
093        RVMMethod caller, callee;
094        caller = getMethod(callerRef);
095
096        @SuppressWarnings("unused") // serves as doco - token skipped
097        int callerSize = Integer.parseInt(parser.nextToken());
098        int bci = Integer.parseInt(parser.nextToken());
099        MemberReference calleeKey = MemberReference.parse(parser, boot);
100        if (calleeKey == null) return;
101        MethodReference calleeRef = calleeKey.asMethodReference();
102        callee = getMethod(calleeRef);
103
104        @SuppressWarnings("unused") // serves as doco - token skipped
105        int calleeSize = Integer.parseInt(parser.nextToken());
106        parser.nextToken(); // skip "weight:"
107        float weight = Float.parseFloat(parser.nextToken());
108        if ((caller == null) || (callee == null)) {
109          Controller.dcg.incrementUnResolvedEdge(callerRef, bci, calleeRef, weight);
110        } else {
111          Controller.dcg.incrementEdge(caller, bci, callee, weight);
112        }
113      } catch (Exception e) {
114        VM.sysWriteln("Caught exception: " + e);
115      }
116    } else {
117      VM.sysFail("Format error in dynamic call graph file");
118    }
119  }
120
121  /**
122   * Establish the RVMMethod for a given MethodReference gracefully.
123   *
124   * @param ref The MethodReference
125   * @return The RVMMethod, or {@code null} on failure.
126   */
127  private static RVMMethod getMethod(MethodReference ref) {
128    if (ref.getType().getClassLoader() == RVMClassLoader.getApplicationClassLoader()) {
129      try {
130        return ref.resolve();
131      } catch (NoClassDefFoundError e) {
132        if (Controller.options.BULK_COMPILATION_VERBOSITY >= 1)
133          VM.sysWriteln("Warning: could not define class: " + ref.getType());
134        return null;
135      } catch (NoSuchMethodError e) {
136        if (Controller.options.BULK_COMPILATION_VERBOSITY >= 1)
137          VM.sysWriteln("Warning: could not load method: " + ref);
138        return null;
139      }
140    } else {
141      return ref.getResolvedMember();
142    }
143  }
144}
145
146
147
148
149