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 } 188 } 189 190 public MethodData(Address addr) { 191 super(addr); 192 } 193 194 public boolean isMethodData() { return true; } 195 196 private static long baseOffset; 197 private static CIntField size; 198 private static MetadataField method; 199 private static CIntField dataSize; 200 private static AddressField data; 201 202 public static int sizeofMethodDataOopDesc; 203 public static int cellSize; 204 205 public Method getMethod() { 206 return (Method) method.getValue(this); 207 } 208 209 public void printValueOn(PrintStream tty) { 210 Method m = getMethod(); 211 tty.print("MethodData for " + m.getName().asString() + m.getSignature().asString()); 212 } 213 214 public void iterateFields(MetadataVisitor visitor) { 215 super.iterateFields(visitor); 216 visitor.doMetadata(method, true); 217 visitor.doCInt(size, true); 218 } 219 220 int dataSize() { 221 if (dataSize == null) { 222 return 0; 223 } else { 224 return (int)dataSize.getValue(getAddress()); 225 } 226 } 227 228 boolean outOfBounds(int dataIndex) { 229 return dataIndex >= dataSize(); 230 } 231 232 ProfileData dataAt(int dataIndex) { 233 if (outOfBounds(dataIndex)) { 234 return null; 235 } 236 DataLayout dataLayout = new DataLayout(this, dataIndex + (int)data.getOffset()); 237 238 switch (dataLayout.tag()) { 239 case DataLayout.noTag: 240 default: 241 throw new InternalError(dataIndex + " " + dataSize() + " " + dataLayout.tag()); 242 case DataLayout.bitDataTag: 243 return new BitData(dataLayout); 244 case DataLayout.counterDataTag: 245 return new CounterData(dataLayout); 246 case DataLayout.jumpDataTag: 247 return new JumpData(dataLayout); 248 case DataLayout.receiverTypeDataTag: 249 return new ReceiverTypeData(dataLayout); 250 case DataLayout.virtualCallDataTag: 251 return new VirtualCallData(dataLayout); 252 case DataLayout.retDataTag: 253 return new RetData(dataLayout); 254 case DataLayout.branchDataTag: 255 return new BranchData(dataLayout); 256 case DataLayout.multiBranchDataTag: 257 return new MultiBranchData(dataLayout); 258 } 259 } 260 261 int dpToDi(int dp) { 262 // this in an offset from the base of the MDO, so convert to offset into _data 263 return dp - (int)data.getOffset(); 264 } 265 266 int firstDi() { return 0; } 267 public ProfileData firstData() { return dataAt(firstDi()); } 268 public ProfileData nextData(ProfileData current) { 269 int currentIndex = dpToDi(current.dp()); 270 int nextIndex = currentIndex + current.sizeInBytes(); 271 return dataAt(nextIndex); 272 } 273 boolean isValid(ProfileData current) { return current != null; } 274 275 public void printDataOn(PrintStream st) { 276 ProfileData data = firstData(); 277 for ( ; isValid(data); data = nextData(data)) { 278 st.print(dpToDi(data.dp())); 279 st.print(" "); 280 // st->fillTo(6); 281 data.printDataOn(st); 282 } 283 } 284 285 private byte[] fetchDataAt(Address base, long offset, long size) { 286 byte[] result = new byte[(int)size]; 287 for (int i = 0; i < size; i++) { 288 result[i] = base.getJByteAt(offset + i); 289 } 290 return result; 291 } 292 293 public byte[] orig() { 294 // fetch the orig MethodData data between header and dataSize 295 return fetchDataAt(getAddress(), 0, sizeofMethodDataOopDesc); 296 } 297 298 public long[] data() { 299 // Read the data as an array of intptr_t elements 300 Address base = getAddress(); 301 long offset = data.getOffset(); 302 int elements = dataSize() / cellSize; 303 long[] result = new long[elements]; 304 for (int i = 0; i < elements; i++) { 305 Address value = base.getAddressAt(offset + i * MethodData.cellSize); 306 if (value != null) { 307 result[i] = value.minus(null); 308 } 309 } 310 return result; 311 } 312 313 // Get a measure of how much mileage the method has on it. 314 int mileageOf(Method method) { 315 long mileage = 0; 316 int iic = method.interpreterInvocationCount(); 317 if (mileage < iic) mileage = iic; 318 319 long ic = method.getInvocationCounter(); 320 long bc = method.getBackedgeCounter(); 321 322 long icval = ic >> 3; 323 if ((ic & 4) != 0) icval += CompileThreshold; 324 if (mileage < icval) mileage = icval; 325 long bcval = bc >> 3; 326 if ((bc & 4) != 0) bcval += CompileThreshold; 327 if (mileage < bcval) mileage = bcval; 328 return (int)mileage; 329 } 330 331 public int currentMileage() { 332 return 20000; 333 } 334 335 public void dumpReplayData(PrintStream out) { 336 Method method = getMethod(); 337 Klass holder = method.getMethodHolder(); 338 out.print("ciMethodData " + 339 holder.getName().asString() + " " + 340 OopUtilities.escapeString(method.getName().asString()) + " " + 341 method.getSignature().asString() + " " + 342 "2" + " " + 343 currentMileage()); 344 byte[] orig = orig(); 345 out.print(" orig " + orig.length); 346 for (int i = 0; i < orig.length; i++) { 347 out.print(" " + (orig[i] & 0xff)); 348 } 349 350 long[] data = data(); 351 out.print(" data " + data.length); 352 for (int i = 0; i < data.length; i++) { 353 out.print(" 0x" + Long.toHexString(data[i])); 354 } 355 int count = 0; 356 for (int round = 0; round < 2; round++) { 357 if (round == 1) out.print(" oops " + count); 358 ProfileData pdata = firstData(); 359 for ( ; isValid(pdata); pdata = nextData(pdata)) { 360 if (pdata instanceof ReceiverTypeData) { 361 ReceiverTypeData vdata = (ReceiverTypeData)pdata; 362 for (int i = 0; i < vdata.rowLimit(); i++) { 363 Klass k = vdata.receiver(i); 364 if (k != null) { 365 if (round == 0) count++; 366 else out.print(" " + 367 (dpToDi(vdata.dp() + 368 vdata.cellOffset(vdata.receiverCellIndex(i))) / cellSize) + " " + 369 k.getName().asString()); 370 } 371 } 372 } else if (pdata instanceof VirtualCallData) { 373 VirtualCallData vdata = (VirtualCallData)pdata; 374 for (int i = 0; i < vdata.rowLimit(); i++) { 375 Klass k = vdata.receiver(i); 376 if (k != null) { 377 if (round == 0) count++; 378 else out.print(" " + 379 (dpToDi(vdata.dp() + 380 vdata.cellOffset(vdata.receiverCellIndex(i))) / cellSize) + " " + 381 k.getName().asString()); 382 } 383 } 384 } 385 } 386 } 387 out.println(); 388 } 389 }