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