1 /* 2 * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.oops; 26 27 import java.io.*; 28 import java.util.*; 29 import sun.jvm.hotspot.debugger.*; 30 import sun.jvm.hotspot.runtime.*; 31 import sun.jvm.hotspot.types.*; 32 import sun.jvm.hotspot.utilities.*; 33 34 // A MethodData provides interpreter profiling information 35 36 public class MethodData extends Metadata { 37 static int TypeProfileWidth = 2; 38 static int BciProfileWidth = 2; 39 static int CompileThreshold; 40 41 static int Reason_many; // indicates presence of several reasons 42 static int Reason_none; // indicates absence of a relevant deopt. 43 static int Reason_LIMIT; 44 static int Reason_RECORDED_LIMIT; // some are not recorded per bc 45 46 private static String[] trapReasonName; 47 48 static String trapReasonName(int reason) { 49 if (reason == Reason_many) return "many"; 50 if (reason < Reason_LIMIT) 51 return trapReasonName[reason]; 52 return "reason" + reason; 53 } 54 55 56 static int trapStateReason(int trapState) { 57 // This assert provides the link between the width of DataLayout.trapBits 58 // and the encoding of "recorded" reasons. It ensures there are enough 59 // bits to store all needed reasons in the per-BCI MDO profile. 60 // assert(dsReasonMask >= reasonRecordedLimit, "enough bits"); 61 int recompileBit = (trapState & dsRecompileBit); 62 trapState -= recompileBit; 63 if (trapState == dsReasonMask) { 64 return Reason_many; 65 } else { 66 // assert((int)reasonNone == 0, "state=0 => Reason_none"); 67 return trapState; 68 } 69 } 70 71 72 static final int dsReasonMask = DataLayout.trapMask >> 1; 73 static final int dsRecompileBit = DataLayout.trapMask - dsReasonMask; 74 75 static boolean trapStateIsRecompiled(int trapState) { 76 return (trapState & dsRecompileBit) != 0; 77 } 78 79 static boolean reasonIsRecordedPerBytecode(int reason) { 80 return reason > Reason_none && reason < Reason_RECORDED_LIMIT; 81 } 82 static int trapStateAddReason(int trapState, int reason) { 83 // assert(reasonIsRecordedPerBytecode((DeoptReason)reason) || reason == reasonMany, "valid reason"); 84 int recompileBit = (trapState & dsRecompileBit); 85 trapState -= recompileBit; 86 if (trapState == dsReasonMask) { 87 return trapState + recompileBit; // already at state lattice bottom 88 } else if (trapState == reason) { 89 return trapState + recompileBit; // the condition is already true 90 } else if (trapState == 0) { 91 return reason + recompileBit; // no condition has yet been true 92 } else { 93 return dsReasonMask + recompileBit; // fall to state lattice bottom 94 } 95 } 96 static int trapStateSetRecompiled(int trapState, boolean z) { 97 if (z) return trapState | dsRecompileBit; 98 else return trapState & ~dsRecompileBit; 99 } 100 101 static String formatTrapState(int trapState) { 102 int reason = trapStateReason(trapState); 103 boolean recompFlag = trapStateIsRecompiled(trapState); 104 // Re-encode the state from its decoded components. 105 int decodedState = 0; 106 if (reasonIsRecordedPerBytecode(reason) || reason == Reason_many) 107 decodedState = trapStateAddReason(decodedState, reason); 108 if (recompFlag) 109 decodedState = trapStateSetRecompiled(decodedState, recompFlag); 110 // If the state re-encodes properly, format it symbolically. 111 // Because this routine is used for debugging and diagnostics, 112 // be robust even if the state is a strange value. 113 if (decodedState != trapState) { 114 // Random buggy state that doesn't decode?? 115 return "#" + trapState; 116 } else { 117 return trapReasonName(reason) + (recompFlag ? " recompiled" : ""); 118 } 119 } 120 121 122 123 static { 124 VM.registerVMInitializedObserver(new Observer() { 125 public void update(Observable o, Object data) { 126 initialize(VM.getVM().getTypeDataBase()); 127 } 128 }); 129 } 130 131 private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { 132 Type type = db.lookupType("MethodData"); 133 baseOffset = type.getSize(); 134 135 size = new CIntField(type.getCIntegerField("_size"), 0); 136 method = new MetadataField(type.getAddressField("_method"), 0); 137 138 VM.Flag[] flags = VM.getVM().getCommandLineFlags(); 139 for (int f = 0; f < flags.length; f++) { 140 VM.Flag flag = flags[f]; 141 if (flag.getName().equals("TypeProfileWidth")) { 142 TypeProfileWidth = (int)flag.getIntx(); 143 } else if (flag.getName().equals("BciProfileWidth")) { 144 BciProfileWidth = (int)flag.getIntx(); 145 } else if (flag.getName().equals("CompileThreshold")) { 146 CompileThreshold = (int)flag.getIntx(); 147 } 148 } 149 150 cellSize = (int)VM.getVM().getAddressSize(); 151 152 dataSize = new CIntField(type.getCIntegerField("_data_size"), 0); 153 data = type.getAddressField("_data[0]"); 154 155 sizeofMethodDataOopDesc = (int)type.getSize();; 156 157 Reason_many = db.lookupIntConstant("Deoptimization::Reason_many").intValue(); 158 Reason_none = db.lookupIntConstant("Deoptimization::Reason_none").intValue(); 159 Reason_LIMIT = db.lookupIntConstant("Deoptimization::Reason_LIMIT").intValue(); 160 Reason_RECORDED_LIMIT = db.lookupIntConstant("Deoptimization::Reason_RECORDED_LIMIT").intValue(); 161 162 trapReasonName = new String[Reason_LIMIT]; 163 164 // Find Deopt reasons 165 Iterator i = db.getIntConstants(); 166 String prefix = "Deoptimization::Reason_"; 167 while (i.hasNext()) { 168 String name = (String)i.next(); 169 if (name.startsWith(prefix)) { 170 // Strip prefix 171 if (!name.endsWith("Reason_many") && 172 !name.endsWith("Reason_LIMIT") && 173 !name.endsWith("Reason_RECORDED_LIMIT")) { 174 String trimmed = name.substring(prefix.length()); 175 int value = db.lookupIntConstant(name).intValue(); 176 if (trapReasonName[value] != null) { 177 throw new InternalError("duplicate reasons: " + trapReasonName[value] + " " + trimmed); 178 } 179 trapReasonName[value] = trimmed; 180 } 181 } 182 } 183 for (int index = 0; index < trapReasonName.length; index++) { 184 if (trapReasonName[index] == null) { 185 throw new InternalError("missing reason for " + index); 186 } 187 System.out.println(trapReasonName[index]); 188 } 189 } 190 191 public MethodData(Address addr) { 192 super(addr); 193 } 194 195 public boolean isMethodData() { return true; } 196 197 private static long baseOffset; 198 private static CIntField size; 199 private static MetadataField method; 200 private static CIntField dataSize; 201 private static AddressField data; 202 203 public static int sizeofMethodDataOopDesc; 204 public static int cellSize; 205 206 public Method getMethod() { 207 return (Method) method.getValue(this); 208 } 209 210 public void printValueOn(PrintStream tty) { 211 Method m = getMethod(); 212 tty.print("MethodData for " + m.getName().asString() + m.getSignature().asString()); 213 } 214 215 public void iterateFields(MetadataVisitor visitor) { 216 super.iterateFields(visitor); 217 visitor.doMetadata(method, true); 218 visitor.doCInt(size, true); 219 } 220 221 int dataSize() { 222 if (dataSize == null) { 223 return 0; 224 } else { 225 return (int)dataSize.getValue(getAddress()); 226 } 227 } 228 229 boolean outOfBounds(int dataIndex) { 230 return dataIndex >= dataSize(); 231 } 232 233 ProfileData dataAt(int dataIndex) { 234 if (outOfBounds(dataIndex)) { 235 return null; 236 } 237 DataLayout dataLayout = new DataLayout(this, dataIndex + (int)data.getOffset()); 238 239 switch (dataLayout.tag()) { 240 case DataLayout.noTag: 241 default: 242 throw new InternalError(dataIndex + " " + dataSize() + " " + dataLayout.tag()); 243 case DataLayout.bitDataTag: 244 return new BitData(dataLayout); 245 case DataLayout.counterDataTag: 246 return new CounterData(dataLayout); 247 case DataLayout.jumpDataTag: 248 return new JumpData(dataLayout); 249 case DataLayout.receiverTypeDataTag: 250 return new ReceiverTypeData(dataLayout); 251 case DataLayout.virtualCallDataTag: 252 return new VirtualCallData(dataLayout); 253 case DataLayout.retDataTag: 254 return new RetData(dataLayout); 255 case DataLayout.branchDataTag: 256 return new BranchData(dataLayout); 257 case DataLayout.multiBranchDataTag: 258 return new MultiBranchData(dataLayout); 259 } 260 } 261 262 int dpToDi(int dp) { 263 // this in an offset from the base of the MDO, so convert to offset into _data 264 return dp - (int)data.getOffset(); 265 } 266 267 int firstDi() { return 0; } 268 public ProfileData firstData() { return dataAt(firstDi()); } 269 public ProfileData nextData(ProfileData current) { 270 int currentIndex = dpToDi(current.dp()); 271 int nextIndex = currentIndex + current.sizeInBytes(); 272 return dataAt(nextIndex); 273 } 274 boolean isValid(ProfileData current) { return current != null; } 275 276 public void printDataOn(PrintStream st) { 277 ProfileData data = firstData(); 278 for ( ; isValid(data); data = nextData(data)) { 279 st.print(dpToDi(data.dp())); 280 st.print(" "); 281 // st->fillTo(6); 282 data.printDataOn(st); 283 } 284 } 285 286 private byte[] fetchDataAt(Address base, long offset, long size) { 287 byte[] result = new byte[(int)size]; 288 for (int i = 0; i < size; i++) { 289 result[i] = base.getJByteAt(offset + i); 290 } 291 return result; 292 } 293 294 public byte[] orig() { 295 // fetch the orig MethodData data between header and dataSize 296 return fetchDataAt(getAddress(), 0, sizeofMethodDataOopDesc); 297 } 298 299 public long[] data() { 300 // Read the data as an array of intptr_t elements 301 Address base = getAddress(); 302 long offset = data.getOffset(); 303 int elements = dataSize() / cellSize; 304 long[] result = new long[elements]; 305 for (int i = 0; i < elements; i++) { 306 Address value = base.getAddressAt(offset + i * MethodData.cellSize); 307 if (value != null) { 308 result[i] = value.minus(null); 309 } 310 } 311 return result; 312 } 313 314 // Get a measure of how much mileage the method has on it. 315 int mileageOf(Method method) { 316 long mileage = 0; 317 int iic = method.interpreterInvocationCount(); 318 if (mileage < iic) mileage = iic; 319 320 long ic = method.getInvocationCounter(); 321 long bc = method.getBackedgeCounter(); 322 323 long icval = ic >> 3; 324 if ((ic & 4) != 0) icval += CompileThreshold; 325 if (mileage < icval) mileage = icval; 326 long bcval = bc >> 3; 327 if ((bc & 4) != 0) bcval += CompileThreshold; 328 if (mileage < bcval) mileage = bcval; 329 return (int)mileage; 330 } 331 332 public int currentMileage() { 333 return 20000; 334 } 335 336 public void dumpReplayData(PrintStream out) { 337 Method method = getMethod(); 338 Klass holder = method.getMethodHolder(); 339 out.print("ciMethodData " + 340 holder.getName().asString() + " " + 341 OopUtilities.escapeString(method.getName().asString()) + " " + 342 method.getSignature().asString() + " " + 343 "2" + " " + 344 currentMileage()); 345 byte[] orig = orig(); 346 out.print(" orig " + orig.length); 347 for (int i = 0; i < orig.length; i++) { 348 out.print(" " + (orig[i] & 0xff)); 349 } 350 351 long[] data = data(); 352 out.print(" data " + data.length); 353 for (int i = 0; i < data.length; i++) { 354 out.print(" 0x" + Long.toHexString(data[i])); 355 } 356 int count = 0; 357 for (int round = 0; round < 2; round++) { 358 if (round == 1) out.print(" oops " + count); 359 ProfileData pdata = firstData(); 360 for ( ; isValid(pdata); pdata = nextData(pdata)) { 361 if (pdata instanceof ReceiverTypeData) { 362 ReceiverTypeData vdata = (ReceiverTypeData)pdata; 363 for (int i = 0; i < vdata.rowLimit(); i++) { 364 Klass k = vdata.receiver(i); 365 if (k != null) { 366 if (round == 0) count++; 367 else out.print(" " + 368 (dpToDi(vdata.dp() + 369 vdata.cellOffset(vdata.receiverCellIndex(i))) / cellSize) + " " + 370 k.getName().asString()); 371 } 372 } 373 } else if (pdata instanceof VirtualCallData) { 374 VirtualCallData vdata = (VirtualCallData)pdata; 375 for (int i = 0; i < vdata.rowLimit(); i++) { 376 Klass k = vdata.receiver(i); 377 if (k != null) { 378 if (round == 0) count++; 379 else out.print(" " + 380 (dpToDi(vdata.dp() + 381 vdata.cellOffset(vdata.receiverCellIndex(i))) / cellSize) + " " + 382 k.getName().asString()); 383 } 384 } 385 } 386 } 387 } 388 out.println(); 389 } 390 }