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 < classloader, classname, method, signature> method_size byte_code_index <callee_classloader, classname, method, signature> method_size weight: weight 035 * </pre> 036 * Where the types and meanings of the fields is as follows: 037 * <ul> 038 * <li><code><signature></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