1 /*
2  * Copyright (c) 2000, 2016, 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 MethodProfileWidth = 0;
40   static int CompileThreshold;
41 
42   static int Reason_many;                 // indicates presence of several reasons
43   static int Reason_none;                 // indicates absence of a relevant deopt.
44   static int Reason_LIMIT;
45   static int Reason_RECORDED_LIMIT;       // some are not recorded per bc
46 
47   private static String[] trapReasonName;
48 
trapReasonName(int reason)49   static String trapReasonName(int reason) {
50     if (reason == Reason_many)  return "many";
51     if (reason < Reason_LIMIT)
52       return trapReasonName[reason];
53     return "reason" + reason;
54   }
55 
56 
trapStateReason(int trapState)57   static int trapStateReason(int trapState) {
58     // This assert provides the link between the width of DataLayout.trapBits
59     // and the encoding of "recorded" reasons.  It ensures there are enough
60     // bits to store all needed reasons in the per-BCI MDO profile.
61     // assert(dsReasonMask >= reasonRecordedLimit, "enough bits");
62     int recompileBit = (trapState & dsRecompileBit);
63     trapState -= recompileBit;
64     if (trapState == dsReasonMask) {
65       return Reason_many;
66     } else {
67       // assert((int)reasonNone == 0, "state=0 => Reason_none");
68       return trapState;
69     }
70   }
71 
72 
73   static final int dsReasonMask   = DataLayout.trapMask >> 1;
74   static final int dsRecompileBit = DataLayout.trapMask - dsReasonMask;
75 
trapStateIsRecompiled(int trapState)76   static boolean trapStateIsRecompiled(int trapState) {
77     return (trapState & dsRecompileBit) != 0;
78   }
79 
reasonIsRecordedPerBytecode(int reason)80   static boolean reasonIsRecordedPerBytecode(int reason) {
81     return reason > Reason_none && reason < Reason_RECORDED_LIMIT;
82   }
trapStateAddReason(int trapState, int reason)83   static int trapStateAddReason(int trapState, int reason) {
84     // assert(reasonIsRecordedPerBytecode((DeoptReason)reason) || reason == reasonMany, "valid reason");
85     int recompileBit = (trapState & dsRecompileBit);
86     trapState -= recompileBit;
87     if (trapState == dsReasonMask) {
88       return trapState + recompileBit;     // already at state lattice bottom
89     } else if (trapState == reason) {
90       return trapState + recompileBit;     // the condition is already true
91     } else if (trapState == 0) {
92       return reason + recompileBit;          // no condition has yet been true
93     } else {
94       return dsReasonMask + recompileBit;  // fall to state lattice bottom
95     }
96   }
trapStateSetRecompiled(int trapState, boolean z)97   static int trapStateSetRecompiled(int trapState, boolean z) {
98     if (z)  return trapState |  dsRecompileBit;
99     else    return trapState & ~dsRecompileBit;
100   }
101 
formatTrapState(int trapState)102   static String formatTrapState(int trapState) {
103     int reason      = trapStateReason(trapState);
104     boolean     recompFlag = trapStateIsRecompiled(trapState);
105     // Re-encode the state from its decoded components.
106     int decodedState = 0;
107     if (reasonIsRecordedPerBytecode(reason) || reason == Reason_many)
108       decodedState = trapStateAddReason(decodedState, reason);
109     if (recompFlag)
110       decodedState = trapStateSetRecompiled(decodedState, recompFlag);
111     // If the state re-encodes properly, format it symbolically.
112     // Because this routine is used for debugging and diagnostics,
113     // be robust even if the state is a strange value.
114     if (decodedState != trapState) {
115       // Random buggy state that doesn't decode??
116       return "#" + trapState;
117     } else {
118       return trapReasonName(reason) + (recompFlag ? " recompiled" : "");
119     }
120   }
121 
122 
123 
124   static {
VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { initialize(VM.getVM().getTypeDataBase()); } })125     VM.registerVMInitializedObserver(new Observer() {
126         public void update(Observable o, Object data) {
127           initialize(VM.getVM().getTypeDataBase());
128         }
129       });
130   }
131 
initialize(TypeDataBase db)132   private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
133     Type type      = db.lookupType("MethodData");
134     baseOffset     = type.getSize();
135 
136     size           = new CIntField(type.getCIntegerField("_size"), 0);
137     method         = new MetadataField(type.getAddressField("_method"), 0);
138 
139     VM.Flag[] flags = VM.getVM().getCommandLineFlags();
140     for (int f = 0; f < flags.length; f++) {
141       VM.Flag flag = flags[f];
142       if (flag.getName().equals("TypeProfileWidth")) {
143         TypeProfileWidth = (int)flag.getIntx();
144       } else if (flag.getName().equals("BciProfileWidth")) {
145         BciProfileWidth = (int)flag.getIntx();
146       } else if (flag.getName().equals("MethodProfileWidth")) {
147         MethodProfileWidth = (int)flag.getIntx();
148       } else if (flag.getName().equals("CompileThreshold")) {
149         CompileThreshold = (int)flag.getIntx();
150       }
151     }
152 
153     cellSize = (int)VM.getVM().getAddressSize();
154 
155     dataSize     = new CIntField(type.getCIntegerField("_data_size"), 0);
156     data         = type.getAddressField("_data[0]");
157 
158     parametersTypeDataDi = new CIntField(type.getCIntegerField("_parameters_type_data_di"), 0);
159 
160     sizeofMethodDataOopDesc = (int)type.getSize();
161 
162     Reason_many            = db.lookupIntConstant("Deoptimization::Reason_many").intValue();
163     Reason_none            = db.lookupIntConstant("Deoptimization::Reason_none").intValue();
164     Reason_LIMIT           = db.lookupIntConstant("Deoptimization::Reason_LIMIT").intValue();
165     Reason_RECORDED_LIMIT  = db.lookupIntConstant("Deoptimization::Reason_RECORDED_LIMIT").intValue();
166 
167     trapReasonName = new String[Reason_LIMIT];
168 
169     // Find Deopt reasons
170     Iterator i = db.getIntConstants();
171     String prefix = "Deoptimization::Reason_";
172     while (i.hasNext()) {
173       String name = (String)i.next();
174       if (name.startsWith(prefix)) {
175         // Strip prefix
176         if (!name.endsWith("Reason_many") &&
177             !name.endsWith("Reason_LIMIT") &&
178             !name.endsWith("Reason_RECORDED_LIMIT")) {
179           String trimmed = name.substring(prefix.length());
180           int value = db.lookupIntConstant(name).intValue();
181           if (trapReasonName[value] != null) {
182             throw new InternalError("duplicate reasons: " + trapReasonName[value] + " " + trimmed);
183           }
184           trapReasonName[value] = trimmed;
185         }
186       }
187     }
188     for (int index = 0; index < trapReasonName.length; index++) {
189       if (trapReasonName[index] == null) {
190         throw new InternalError("missing reason for " + index);
191       }
192     }
193   }
194 
MethodData(Address addr)195   public MethodData(Address addr) {
196     super(addr);
197   }
198 
getKlassAtAddress(Address addr)199   public Klass getKlassAtAddress(Address addr) {
200     return (Klass)Metadata.instantiateWrapperFor(addr);
201   }
202 
getMethodAtAddress(Address addr)203   public Method getMethodAtAddress(Address addr) {
204     return (Method)Metadata.instantiateWrapperFor(addr);
205   }
206 
printKlassValueOn(Klass klass, PrintStream st)207   public void printKlassValueOn(Klass klass, PrintStream st) {
208     klass.printValueOn(st);
209   }
210 
printMethodValueOn(Method method, PrintStream st)211   public void printMethodValueOn(Method method, PrintStream st) {
212     method.printValueOn(st);
213   }
214 
isMethodData()215   public boolean isMethodData()        { return true; }
216 
217   private static long baseOffset;
218   private static CIntField size;
219   private static MetadataField  method;
220   private static CIntField dataSize;
221   private static AddressField data;
222   private static CIntField parametersTypeDataDi;
223   public static int sizeofMethodDataOopDesc;
224   public static int cellSize;
225 
getMethod()226   public Method getMethod() {
227     return (Method) method.getValue(this);
228   }
229 
printValueOn(PrintStream tty)230   public void printValueOn(PrintStream tty) {
231     Method m = getMethod();
232     tty.print("MethodData for " + m.getName().asString() + m.getSignature().asString());
233   }
234 
iterateFields(MetadataVisitor visitor)235   public void iterateFields(MetadataVisitor visitor) {
236     super.iterateFields(visitor);
237     visitor.doMetadata(method, true);
238       visitor.doCInt(size, true);
239     }
240 
dataSize()241   int dataSize() {
242     if (dataSize == null) {
243       return 0;
244     } else {
245       return (int)dataSize.getValue(getAddress());
246     }
247   }
248 
sizeInBytes()249   int sizeInBytes() {
250     if (size == null) {
251       return 0;
252     } else {
253       return (int)size.getValue(getAddress());
254     }
255   }
256 
size()257   int size() {
258     return (int)alignSize(VM.getVM().alignUp(sizeInBytes(), VM.getVM().getBytesPerWord())/VM.getVM().getBytesPerWord());
259   }
260 
parametersTypeData()261   ParametersTypeData<Klass,Method> parametersTypeData() {
262     int di = (int)parametersTypeDataDi.getValue(getAddress());
263     if (di == -1 || di == -2) {
264       return null;
265     }
266     DataLayout dataLayout = new DataLayout(this, di + (int)data.getOffset());
267     return new ParametersTypeData<Klass,Method>(this, dataLayout);
268   }
269 
outOfBounds(int dataIndex)270   boolean outOfBounds(int dataIndex) {
271     return dataIndex >= dataSize();
272   }
273 
dataAt(int dataIndex)274   ProfileData dataAt(int dataIndex) {
275     if (outOfBounds(dataIndex)) {
276       return null;
277     }
278     DataLayout dataLayout = new DataLayout(this, dataIndex + (int)data.getOffset());
279 
280     switch (dataLayout.tag()) {
281     case DataLayout.noTag:
282     default:
283       throw new InternalError(dataIndex + " " + dataSize() + " " + dataLayout.tag());
284     case DataLayout.bitDataTag:
285       return new BitData(dataLayout);
286     case DataLayout.counterDataTag:
287       return new CounterData(dataLayout);
288     case DataLayout.jumpDataTag:
289       return new JumpData(dataLayout);
290     case DataLayout.receiverTypeDataTag:
291       return new ReceiverTypeData<Klass,Method>(this, dataLayout);
292     case DataLayout.virtualCallDataTag:
293       return new VirtualCallData<Klass,Method>(this, dataLayout);
294     case DataLayout.retDataTag:
295       return new RetData(dataLayout);
296     case DataLayout.branchDataTag:
297       return new BranchData(dataLayout);
298     case DataLayout.multiBranchDataTag:
299       return new MultiBranchData(dataLayout);
300     case DataLayout.callTypeDataTag:
301       return new CallTypeData<Klass,Method>(this, dataLayout);
302     case DataLayout.virtualCallTypeDataTag:
303       return new VirtualCallTypeData<Klass,Method>(this, dataLayout);
304     case DataLayout.parametersTypeDataTag:
305       return new ParametersTypeData<Klass,Method>(this, dataLayout);
306     }
307   }
308 
dpToDi(int dp)309   int dpToDi(int dp) {
310     // this in an offset from the base of the MDO, so convert to offset into _data
311     return dp - (int)data.getOffset();
312   }
313 
firstDi()314   int firstDi() { return 0; }
firstData()315   public ProfileData firstData() { return dataAt(firstDi()); }
nextData(ProfileData current)316   public ProfileData nextData(ProfileData current) {
317     int currentIndex = dpToDi(current.dp());
318     int nextIndex = currentIndex + current.sizeInBytes();
319     return dataAt(nextIndex);
320   }
isValid(ProfileData current)321   boolean isValid(ProfileData current) { return current != null; }
322 
limitDataPosition()323   DataLayout limitDataPosition() {
324     return new DataLayout(this, dataSize() + (int)data.getOffset());
325   }
326 
extraDataBase()327   DataLayout extraDataBase() {
328     return limitDataPosition();
329   }
330 
extraDataLimit()331   DataLayout extraDataLimit() {
332     return new DataLayout(this, sizeInBytes());
333   }
334 
extraNbCells(DataLayout dataLayout)335   static public int extraNbCells(DataLayout dataLayout) {
336     int nbCells = 0;
337     switch(dataLayout.tag()) {
338     case DataLayout.bitDataTag:
339     case DataLayout.noTag:
340       nbCells = BitData.staticCellCount();
341       break;
342     case DataLayout.speculativeTrapDataTag:
343       nbCells = SpeculativeTrapData.staticCellCount();
344       break;
345     default:
346       throw new InternalError("unexpected tag " +  dataLayout.tag());
347     }
348     return nbCells;
349   }
350 
nextExtra(DataLayout dataLayout)351   DataLayout nextExtra(DataLayout dataLayout) {
352     return new DataLayout(this, dataLayout.dp() + DataLayout.computeSizeInBytes(extraNbCells(dataLayout)));
353   }
354 
printDataOn(PrintStream st)355   public void printDataOn(PrintStream st) {
356     if (parametersTypeData() != null) {
357       parametersTypeData().printDataOn(st);
358     }
359     ProfileData data = firstData();
360     for ( ; isValid(data); data = nextData(data)) {
361       st.print(dpToDi(data.dp()));
362       st.print(" ");
363       // st->fillTo(6);
364       data.printDataOn(st);
365     }
366     st.println("--- Extra data:");
367     DataLayout dp    = extraDataBase();
368     DataLayout end   = extraDataLimit();
369     for (;; dp = nextExtra(dp)) {
370       switch(dp.tag()) {
371       case DataLayout.noTag:
372         continue;
373       case DataLayout.bitDataTag:
374         data = new BitData(dp);
375         break;
376       case DataLayout.speculativeTrapDataTag:
377         data = new SpeculativeTrapData<Klass,Method>(this, dp);
378         break;
379       case DataLayout.argInfoDataTag:
380         data = new ArgInfoData(dp);
381         dp = end; // ArgInfoData is at the end of extra data section.
382         break;
383       default:
384         throw new InternalError("unexpected tag " +  dp.tag());
385       }
386       st.print(dpToDi(data.dp()));
387       st.print(" ");
388       data.printDataOn(st);
389       if (dp == end) return;
390     }
391   }
392 
fetchDataAt(Address base, long offset, long size)393   private byte[] fetchDataAt(Address base, long offset, long size) {
394     byte[] result = new byte[(int)size];
395     for (int i = 0; i < size; i++) {
396       result[i] = base.getJByteAt(offset + i);
397     }
398     return result;
399   }
400 
orig()401   public byte[] orig() {
402     // fetch the orig MethodData data between header and dataSize
403     return fetchDataAt(getAddress(), 0, sizeofMethodDataOopDesc);
404   }
405 
data()406   public long[] data() {
407     // Read the data as an array of intptr_t elements
408     Address base = getAddress();
409     long offset = data.getOffset();
410     int elements = dataSize() / cellSize;
411     long[] result = new long[elements];
412     for (int i = 0; i < elements; i++) {
413       Address value = base.getAddressAt(offset + i * MethodData.cellSize);
414       if (value != null) {
415         result[i] = value.minus(null);
416       }
417     }
418     return result;
419   }
420 
421   // Get a measure of how much mileage the method has on it.
mileageOf(Method method)422   int mileageOf(Method method) {
423     long mileage = 0;
424     int iic = method.interpreterInvocationCount();
425     if (mileage < iic)  mileage = iic;
426 
427     long ic = method.getInvocationCount();
428     long bc = method.getBackedgeCount();
429 
430     long icval = ic >> 3;
431     if ((ic & 4) != 0) icval += CompileThreshold;
432     if (mileage < icval)  mileage = icval;
433     long bcval = bc >> 3;
434     if ((bc & 4) != 0) bcval += CompileThreshold;
435     if (mileage < bcval)  mileage = bcval;
436     return (int)mileage;
437   }
438 
currentMileage()439   public int currentMileage() {
440     return 20000;
441   }
442 
dumpReplayDataTypeHelper(PrintStream out, int round, int count, int index, ProfileData pdata, Klass k)443   int dumpReplayDataTypeHelper(PrintStream out, int round, int count, int index, ProfileData pdata, Klass k) {
444     if (k != null) {
445       if (round == 0) count++;
446       else out.print(" " +
447                      (dpToDi(pdata.dp() +
448                              pdata.cellOffset(index)) / cellSize) + " " +
449                      k.getName().asString());
450     }
451     return count;
452   }
453 
dumpReplayDataReceiverTypeHelper(PrintStream out, int round, int count, ReceiverTypeData<Klass,Method> vdata)454   int dumpReplayDataReceiverTypeHelper(PrintStream out, int round, int count, ReceiverTypeData<Klass,Method> vdata) {
455     for (int i = 0; i < vdata.rowLimit(); i++) {
456       Klass k = vdata.receiver(i);
457       count = dumpReplayDataTypeHelper(out, round, count, vdata.receiverCellIndex(i), vdata, k);
458     }
459     return count;
460   }
461 
dumpReplayDataCallTypeHelper(PrintStream out, int round, int count, CallTypeDataInterface<Klass> callTypeData)462   int dumpReplayDataCallTypeHelper(PrintStream out, int round, int count, CallTypeDataInterface<Klass> callTypeData) {
463     if (callTypeData.hasArguments()) {
464       for (int i = 0; i < callTypeData.numberOfArguments(); i++) {
465         count = dumpReplayDataTypeHelper(out, round, count, callTypeData.argumentTypeIndex(i), (ProfileData)callTypeData, callTypeData.argumentType(i));
466       }
467     }
468     if (callTypeData.hasReturn()) {
469       count = dumpReplayDataTypeHelper(out, round, count, callTypeData.returnTypeIndex(), (ProfileData)callTypeData, callTypeData.returnType());
470     }
471     return count;
472   }
473 
dumpReplayDataExtraDataHelper(PrintStream out, int round, int count)474   int dumpReplayDataExtraDataHelper(PrintStream out, int round, int count) {
475     DataLayout dp    = extraDataBase();
476     DataLayout end   = extraDataLimit();
477 
478     for (;dp != end; dp = nextExtra(dp)) {
479       switch(dp.tag()) {
480       case DataLayout.noTag:
481       case DataLayout.argInfoDataTag:
482         return count;
483       case DataLayout.bitDataTag:
484         break;
485       case DataLayout.speculativeTrapDataTag: {
486         SpeculativeTrapData<Klass,Method> data = new SpeculativeTrapData<Klass,Method>(this, dp);
487         Method m = data.method();
488         if (m != null) {
489           if (round == 0) {
490             count++;
491           } else {
492             out.print(" " +  (dpToDi(data.dp() + data.cellOffset(SpeculativeTrapData.methodIndex())) / cellSize) + " " +  m.nameAsAscii());
493           }
494         }
495         break;
496       }
497       default:
498         throw new InternalError("bad tag "  + dp.tag());
499       }
500     }
501     return count;
502   }
503 
dumpReplayData(PrintStream out)504   public void dumpReplayData(PrintStream out) {
505     Method method = getMethod();
506     out.print("ciMethodData " + method.nameAsAscii()
507               + " " + "2" + " " +
508               currentMileage());
509     byte[] orig = orig();
510     out.print(" orig " + orig.length);
511     for (int i = 0; i < orig.length; i++) {
512       out.print(" " + (orig[i] & 0xff));
513     }
514 
515     long[] data = data();
516     out.print(" data " +  data.length);
517     for (int i = 0; i < data.length; i++) {
518       out.print(" 0x" + Long.toHexString(data[i]));
519     }
520     int count = 0;
521     ParametersTypeData<Klass,Method> parameters = parametersTypeData();
522     for (int round = 0; round < 2; round++) {
523       if (round == 1) out.print(" oops " + count);
524       ProfileData pdata = firstData();
525       for ( ; isValid(pdata); pdata = nextData(pdata)) {
526         if (pdata instanceof ReceiverTypeData) {
527           count = dumpReplayDataReceiverTypeHelper(out, round, count, (ReceiverTypeData<Klass,Method>)pdata);
528         }
529         if (pdata instanceof CallTypeDataInterface) {
530           count = dumpReplayDataCallTypeHelper(out, round, count, (CallTypeDataInterface<Klass>)pdata);
531         }
532       }
533       if (parameters != null) {
534         for (int i = 0; i < parameters.numberOfParameters(); i++) {
535           count = dumpReplayDataTypeHelper(out, round, count, ParametersTypeData.typeIndex(i), parameters, parameters.type(i));
536         }
537       }
538     }
539     count = 0;
540     for (int round = 0; round < 2; round++) {
541       if (round == 1) out.print(" methods " + count);
542       count = dumpReplayDataExtraDataHelper(out, round, count);
543     }
544     out.println();
545   }
546 }
547