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 }