1 /*
   2  * Copyright (c) 2000, 2013, 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 implements MethodDataInterface<Klass,Method> {
  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     parametersTypeDataDi = new CIntField(type.getCIntegerField("_parameters_type_data_di"), 0);
 156 
 157     sizeofMethodDataOopDesc = (int)type.getSize();;
 158 
 159     Reason_many            = db.lookupIntConstant("Deoptimization::Reason_many").intValue();
 160     Reason_none            = db.lookupIntConstant("Deoptimization::Reason_none").intValue();
 161     Reason_LIMIT           = db.lookupIntConstant("Deoptimization::Reason_LIMIT").intValue();
 162     Reason_RECORDED_LIMIT  = db.lookupIntConstant("Deoptimization::Reason_RECORDED_LIMIT").intValue();
 163 
 164     trapReasonName = new String[Reason_LIMIT];
 165 
 166     // Find Deopt reasons
 167     Iterator i = db.getIntConstants();
 168     String prefix = "Deoptimization::Reason_";
 169     while (i.hasNext()) {
 170       String name = (String)i.next();
 171       if (name.startsWith(prefix)) {
 172         // Strip prefix
 173         if (!name.endsWith("Reason_many") &&
 174             !name.endsWith("Reason_LIMIT") &&
 175             !name.endsWith("Reason_RECORDED_LIMIT")) {
 176           String trimmed = name.substring(prefix.length());
 177           int value = db.lookupIntConstant(name).intValue();
 178           if (trapReasonName[value] != null) {
 179             throw new InternalError("duplicate reasons: " + trapReasonName[value] + " " + trimmed);
 180           }
 181           trapReasonName[value] = trimmed;
 182         }
 183       }
 184     }
 185     for (int index = 0; index < trapReasonName.length; index++) {
 186       if (trapReasonName[index] == null) {
 187         throw new InternalError("missing reason for " + index);
 188       }
 189     }
 190   }
 191 
 192   public MethodData(Address addr) {
 193     super(addr);
 194   }
 195 
 196   public Klass getKlassAtAddress(Address addr) {
 197     return (Klass)Metadata.instantiateWrapperFor(addr);
 198   }
 199 
 200   public Method getMethodAtAddress(Address addr) {
 201     return (Method)Metadata.instantiateWrapperFor(addr);
 202   }
 203 
 204   public void printKlassValueOn(Klass klass, PrintStream st) {
 205     klass.printValueOn(st);
 206   }
 207 
 208   public void printMethodValueOn(Method method, PrintStream st) {
 209     method.printValueOn(st);
 210   }
 211 
 212   public boolean isMethodData()        { return true; }
 213 
 214   private static long baseOffset;
 215   private static CIntField size;
 216   private static MetadataField  method;
 217   private static CIntField dataSize;
 218   private static AddressField data;
 219   private static CIntField parametersTypeDataDi;
 220   public static int sizeofMethodDataOopDesc;
 221   public static int cellSize;
 222 
 223   public Method getMethod() {
 224     return (Method) method.getValue(this);
 225   }
 226 
 227   public void printValueOn(PrintStream tty) {
 228     Method m = getMethod();
 229     tty.print("MethodData for " + m.getName().asString() + m.getSignature().asString());
 230   }
 231 
 232   public void iterateFields(MetadataVisitor visitor) {
 233     super.iterateFields(visitor);
 234     visitor.doMetadata(method, true);
 235       visitor.doCInt(size, true);
 236     }
 237 
 238   int dataSize() {
 239     if (dataSize == null) {
 240       return 0;
 241     } else {
 242       return (int)dataSize.getValue(getAddress());
 243     }
 244   }
 245 
 246   int sizeInBytes() {
 247     if (size == null) {
 248       return 0;
 249     } else {
 250       return (int)size.getValue(getAddress());
 251     }
 252   }
 253 
 254   int size() {
 255     return (int)alignSize(VM.getVM().alignUp(sizeInBytes(), VM.getVM().getBytesPerWord())/VM.getVM().getBytesPerWord());
 256   }
 257 
 258   ParametersTypeData<Klass,Method> parametersTypeData() {
 259     int di = (int)parametersTypeDataDi.getValue(getAddress());
 260     if (di == -1) {
 261       return null;
 262     }
 263     DataLayout dataLayout = new DataLayout(this, di + (int)data.getOffset());
 264     return new ParametersTypeData<Klass,Method>(this, dataLayout);
 265   }
 266 
 267   boolean outOfBounds(int dataIndex) {
 268     return dataIndex >= dataSize();
 269   }
 270 
 271   ProfileData dataAt(int dataIndex) {
 272     if (outOfBounds(dataIndex)) {
 273       return null;
 274     }
 275     DataLayout dataLayout = new DataLayout(this, dataIndex + (int)data.getOffset());
 276 
 277     switch (dataLayout.tag()) {
 278     case DataLayout.noTag:
 279     default:
 280       throw new InternalError(dataIndex + " " + dataSize() + " " + dataLayout.tag());
 281     case DataLayout.bitDataTag:
 282       return new BitData(dataLayout);
 283     case DataLayout.counterDataTag:
 284       return new CounterData(dataLayout);
 285     case DataLayout.jumpDataTag:
 286       return new JumpData(dataLayout);
 287     case DataLayout.receiverTypeDataTag:
 288       return new ReceiverTypeData<Klass,Method>(this, dataLayout);
 289     case DataLayout.virtualCallDataTag:
 290       return new VirtualCallData<Klass,Method>(this, dataLayout);
 291     case DataLayout.retDataTag:
 292       return new RetData(dataLayout);
 293     case DataLayout.branchDataTag:
 294       return new BranchData(dataLayout);
 295     case DataLayout.multiBranchDataTag:
 296       return new MultiBranchData(dataLayout);
 297     case DataLayout.callTypeDataTag:
 298       return new CallTypeData<Klass,Method>(this, dataLayout);
 299     case DataLayout.virtualCallTypeDataTag:
 300       return new VirtualCallTypeData<Klass,Method>(this, dataLayout);
 301     case DataLayout.parametersTypeDataTag:
 302       return new ParametersTypeData<Klass,Method>(this, dataLayout);
 303     }
 304   }
 305 
 306   int dpToDi(int dp) {
 307     // this in an offset from the base of the MDO, so convert to offset into _data
 308     return dp - (int)data.getOffset();
 309   }
 310 
 311   int firstDi() { return 0; }
 312   public ProfileData firstData() { return dataAt(firstDi()); }
 313   public ProfileData nextData(ProfileData current) {
 314     int currentIndex = dpToDi(current.dp());
 315     int nextIndex = currentIndex + current.sizeInBytes();
 316     return dataAt(nextIndex);
 317   }
 318   boolean isValid(ProfileData current) { return current != null; }
 319 
 320   DataLayout limitDataPosition() {
 321     return new DataLayout(this, dataSize() + (int)data.getOffset());
 322   }
 323 
 324   DataLayout extraDataBase() {
 325     return limitDataPosition();
 326   }
 327 
 328   DataLayout extraDataLimit() {
 329     return new DataLayout(this, sizeInBytes());
 330   }
 331 
 332   static public int extraNbCells(DataLayout dataLayout) {
 333     int nbCells = 0;
 334     switch(dataLayout.tag()) {
 335     case DataLayout.bitDataTag:
 336     case DataLayout.noTag:
 337       nbCells = BitData.staticCellCount();
 338       break;
 339     case DataLayout.speculativeTrapDataTag:
 340       nbCells = SpeculativeTrapData.staticCellCount();
 341       break;
 342     default:
 343       throw new InternalError("unexpected tag " +  dataLayout.tag());
 344     }
 345     return nbCells;
 346   }
 347 
 348   DataLayout nextExtra(DataLayout dataLayout) {
 349     return new DataLayout(this, dataLayout.dp() + DataLayout.computeSizeInBytes(extraNbCells(dataLayout)));
 350   }
 351 
 352   public void printDataOn(PrintStream st) {
 353     if (parametersTypeData() != null) {
 354       parametersTypeData().printDataOn(st);
 355     }
 356     ProfileData data = firstData();
 357     for ( ; isValid(data); data = nextData(data)) {
 358       st.print(dpToDi(data.dp()));
 359       st.print(" ");
 360       // st->fillTo(6);
 361       data.printDataOn(st);
 362     }
 363     st.println("--- Extra data:");
 364     DataLayout dp    = extraDataBase();
 365     DataLayout end   = extraDataLimit();
 366     for (;; dp = nextExtra(dp)) {
 367       switch(dp.tag()) {
 368       case DataLayout.noTag:
 369         continue;
 370       case DataLayout.bitDataTag:
 371         data = new BitData(dp);
 372         break;
 373       case DataLayout.speculativeTrapDataTag:
 374         data = new SpeculativeTrapData<Klass,Method>(this, dp);
 375         break;
 376       case DataLayout.argInfoDataTag:
 377         data = new ArgInfoData(dp);
 378         dp = end; // ArgInfoData is at the end of extra data section.
 379         break;
 380       default:
 381         throw new InternalError("unexpected tag " +  dp.tag());
 382       }
 383       st.print(dpToDi(data.dp()));
 384       st.print(" ");
 385       data.printDataOn(st);
 386       if (dp == end) return;
 387     }
 388   }
 389 
 390   private byte[] fetchDataAt(Address base, long offset, long size) {
 391     byte[] result = new byte[(int)size];
 392     for (int i = 0; i < size; i++) {
 393       result[i] = base.getJByteAt(offset + i);
 394     }
 395     return result;
 396   }
 397 
 398   public byte[] orig() {
 399     // fetch the orig MethodData data between header and dataSize
 400     return fetchDataAt(getAddress(), 0, sizeofMethodDataOopDesc);
 401   }
 402 
 403   public long[] data() {
 404     // Read the data as an array of intptr_t elements
 405     Address base = getAddress();
 406     long offset = data.getOffset();
 407     int elements = dataSize() / cellSize;
 408     long[] result = new long[elements];
 409     for (int i = 0; i < elements; i++) {
 410       Address value = base.getAddressAt(offset + i * MethodData.cellSize);
 411       if (value != null) {
 412         result[i] = value.minus(null);
 413       }
 414     }
 415     return result;
 416   }
 417 
 418   // Get a measure of how much mileage the method has on it.
 419   int mileageOf(Method method) {
 420     long mileage = 0;
 421     int iic = method.interpreterInvocationCount();
 422     if (mileage < iic)  mileage = iic;
 423 
 424     long ic = method.getInvocationCount();
 425     long bc = method.getBackedgeCount();
 426 
 427     long icval = ic >> 3;
 428     if ((ic & 4) != 0) icval += CompileThreshold;
 429     if (mileage < icval)  mileage = icval;
 430     long bcval = bc >> 3;
 431     if ((bc & 4) != 0) bcval += CompileThreshold;
 432     if (mileage < bcval)  mileage = bcval;
 433     return (int)mileage;
 434   }
 435 
 436   public int currentMileage() {
 437     return 20000;
 438   }
 439 
 440   int dumpReplayDataTypeHelper(PrintStream out, int round, int count, int index, ProfileData pdata, Klass k) {
 441     if (k != null) {
 442       if (round == 0) count++;
 443       else out.print(" " +
 444                      (dpToDi(pdata.dp() +
 445                              pdata.cellOffset(index)) / cellSize) + " " +
 446                      k.getName().asString());
 447     }
 448     return count;
 449   }
 450 
 451   int dumpReplayDataReceiverTypeHelper(PrintStream out, int round, int count, ReceiverTypeData<Klass,Method> vdata) {
 452     for (int i = 0; i < vdata.rowLimit(); i++) {
 453       Klass k = vdata.receiver(i);
 454       count = dumpReplayDataTypeHelper(out, round, count, vdata.receiverCellIndex(i), vdata, k);
 455     }
 456     return count;
 457   }
 458 
 459   int dumpReplayDataCallTypeHelper(PrintStream out, int round, int count, CallTypeDataInterface<Klass> callTypeData) {
 460     if (callTypeData.hasArguments()) {
 461       for (int i = 0; i < callTypeData.numberOfArguments(); i++) {
 462         count = dumpReplayDataTypeHelper(out, round, count, callTypeData.argumentTypeIndex(i), (ProfileData)callTypeData, callTypeData.argumentType(i));
 463       }
 464     }
 465     if (callTypeData.hasReturn()) {
 466       count = dumpReplayDataTypeHelper(out, round, count, callTypeData.returnTypeIndex(), (ProfileData)callTypeData, callTypeData.returnType());
 467     }
 468     return count;
 469   }
 470 
 471   int dumpReplayDataExtraDataHelper(PrintStream out, int round, int count) {
 472     DataLayout dp    = extraDataBase();
 473     DataLayout end   = extraDataLimit();
 474 
 475     for (;dp != end; dp = nextExtra(dp)) {
 476       switch(dp.tag()) {
 477       case DataLayout.noTag:
 478       case DataLayout.argInfoDataTag:
 479         return count;
 480       case DataLayout.bitDataTag:
 481         break;
 482       case DataLayout.speculativeTrapDataTag: {
 483         SpeculativeTrapData<Klass,Method> data = new SpeculativeTrapData<Klass,Method>(this, dp);
 484         Method m = data.method();
 485         if (m != null) {
 486           if (round == 0) {
 487             count++;
 488           } else {
 489             out.print(" " +  (dpToDi(data.dp() + data.cellOffset(SpeculativeTrapData.methodIndex())) / cellSize) + " " +  m.nameAsAscii());
 490           }
 491         }
 492         break;
 493       }
 494       default:
 495         throw new InternalError("bad tag "  + dp.tag());
 496       }
 497     }
 498     return count;
 499   }
 500 
 501   public void dumpReplayData(PrintStream out) {
 502     Method method = getMethod();
 503     out.print("ciMethodData " + method.nameAsAscii()
 504               + " " + "2" + " " +
 505               currentMileage());
 506     byte[] orig = orig();
 507     out.print(" orig " + orig.length);
 508     for (int i = 0; i < orig.length; i++) {
 509       out.print(" " + (orig[i] & 0xff));
 510     }
 511 
 512     long[] data = data();
 513     out.print(" data " +  data.length);
 514     for (int i = 0; i < data.length; i++) {
 515       out.print(" 0x" + Long.toHexString(data[i]));
 516     }
 517     int count = 0;
 518     ParametersTypeData<Klass,Method> parameters = parametersTypeData();
 519     for (int round = 0; round < 2; round++) {
 520       if (round == 1) out.print(" oops " + count);
 521       ProfileData pdata = firstData();
 522       for ( ; isValid(pdata); pdata = nextData(pdata)) {
 523         if (pdata instanceof ReceiverTypeData) {
 524           count = dumpReplayDataReceiverTypeHelper(out, round, count, (ReceiverTypeData<Klass,Method>)pdata);
 525         }
 526         if (pdata instanceof CallTypeDataInterface) {
 527           count = dumpReplayDataCallTypeHelper(out, round, count, (CallTypeDataInterface<Klass>)pdata);
 528         }
 529       }
 530       if (parameters != null) {
 531         for (int i = 0; i < parameters.numberOfParameters(); i++) {
 532           count = dumpReplayDataTypeHelper(out, round, count, ParametersTypeData.typeIndex(i), parameters, parameters.type(i));
 533         }
 534       }
 535     }
 536     count = 0;
 537     for (int round = 0; round < 2; round++) {
 538       if (round == 1) out.print(" methods " + count);
 539       count = dumpReplayDataExtraDataHelper(out, round, count);
 540     }
 541     out.println();
 542   }
 543 }
--- EOF ---