1 /*
2  * Copyright (c) 2011, 2020, 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.ci;
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.oops.*;
32 import sun.jvm.hotspot.types.*;
33 import sun.jvm.hotspot.utilities.Observable;
34 import sun.jvm.hotspot.utilities.Observer;
35 
36 public class ciMethodData extends ciMetadata implements MethodDataInterface<ciKlass,ciMethod> {
37   static {
VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { initialize(VM.getVM().getTypeDataBase()); } })38     VM.registerVMInitializedObserver(new Observer() {
39         public void update(Observable o, Object data) {
40           initialize(VM.getVM().getTypeDataBase());
41         }
42       });
43   }
44 
initialize(TypeDataBase db)45   private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
46     Type type      = db.lookupType("ciMethodData");
47     origField = type.getAddressField("_orig");
48     currentMileageField = new CIntField(type.getCIntegerField("_current_mileage"), 0);
49     argReturnedField = new CIntField(type.getCIntegerField("_arg_returned"), 0);
50     argStackField = new CIntField(type.getCIntegerField("_arg_stack"), 0);
51     argLocalField = new CIntField(type.getCIntegerField("_arg_local"), 0);
52     eflagsField = new CIntField(type.getCIntegerField("_eflags"), 0);
53     hintDiField = new CIntField(type.getCIntegerField("_hint_di"), 0);
54     currentMileageField = new CIntField(type.getCIntegerField("_current_mileage"), 0);
55     dataField = type.getAddressField("_data");
56     extraDataSizeField = new CIntField(type.getCIntegerField("_extra_data_size"), 0);
57     dataSizeField = new CIntField(type.getCIntegerField("_data_size"), 0);
58     stateField = new CIntField(type.getCIntegerField("_state"), 0);
59     Type typeMethodData = db.lookupType("MethodData");
60     sizeofMethodDataOopDesc = (int)typeMethodData.getSize();
61     parametersTypeDataDi = new CIntField(typeMethodData.getCIntegerField("_parameters_type_data_di"), 0);
62   }
63 
64   private static AddressField origField;
65   private static CIntField currentMileageField;
66   private static CIntField argReturnedField;
67   private static CIntField argStackField;
68   private static CIntField argLocalField;
69   private static CIntField eflagsField;
70   private static CIntField hintDiField;
71   private static AddressField dataField;
72   private static CIntField extraDataSizeField;
73   private static CIntField dataSizeField;
74   private static CIntField stateField;
75   private static int sizeofMethodDataOopDesc;
76   private static CIntField parametersTypeDataDi;
77 
ciMethodData(Address addr)78   public ciMethodData(Address addr) {
79     super(addr);
80   }
81 
getKlassAtAddress(Address addr)82   public ciKlass getKlassAtAddress(Address addr) {
83     return (ciKlass)ciObjectFactory.getMetadata(addr);
84   }
85 
getMethodAtAddress(Address addr)86   public ciMethod getMethodAtAddress(Address addr) {
87     return (ciMethod)ciObjectFactory.getMetadata(addr);
88   }
89 
printKlassValueOn(ciKlass klass, PrintStream st)90   public void printKlassValueOn(ciKlass klass, PrintStream st) {
91     klass.printValueOn(st);
92   }
93 
printMethodValueOn(ciMethod method, PrintStream st)94   public void printMethodValueOn(ciMethod method, PrintStream st) {
95     method.printValueOn(st);
96   }
97 
fetchDataAt(Address base, long size)98   private byte[] fetchDataAt(Address base, long size) {
99     byte[] result = new byte[(int)size];
100     for (int i = 0; i < size; i++) {
101       result[i] = base.getJByteAt(i);
102     }
103     return result;
104   }
105 
orig()106   public byte[] orig() {
107     // fetch the orig MethodData data between header and dataSize
108     Address base = getAddress().addOffsetTo(origField.getOffset());
109     byte[] result = new byte[MethodData.sizeofMethodDataOopDesc];
110     for (int i = 0; i < MethodData.sizeofMethodDataOopDesc; i++) {
111       result[i] = base.getJByteAt(i);
112     }
113     return result;
114   }
115 
data()116   public  long[] data() {
117     // Read the data as an array of intptr_t elements
118     Address base = dataField.getValue(getAddress());
119     int elements = dataSize() / MethodData.cellSize;
120     long[] result = new long[elements];
121     for (int i = 0; i < elements; i++) {
122       Address value = base.getAddressAt(i * MethodData.cellSize);
123       if (value != null) {
124         result[i] = value.minus(null);
125       }
126     }
127     return result;
128   }
129 
dataSize()130   int dataSize() {
131     return (int)dataSizeField.getValue(getAddress());
132   }
133 
extraDataSize()134   int extraDataSize() {
135     return (int)extraDataSizeField.getValue(getAddress());
136   }
137 
state()138   int state() {
139     return (int)stateField.getValue(getAddress());
140   }
141 
currentMileage()142   int currentMileage() {
143     return (int)currentMileageField.getValue(getAddress());
144   }
145 
outOfBounds(int dataIndex)146   boolean outOfBounds(int dataIndex) {
147     return dataIndex >= dataSize();
148   }
149 
parametersTypeData()150   ParametersTypeData<ciKlass,ciMethod> parametersTypeData() {
151     Address base = getAddress().addOffsetTo(origField.getOffset());
152     int di = (int)parametersTypeDataDi.getValue(base);
153     if (di == -1 || di == -2) {
154       return null;
155     }
156     DataLayout dataLayout = new DataLayout(dataField.getValue(getAddress()), di);
157     return new ParametersTypeData<ciKlass,ciMethod>(this, dataLayout);
158   }
159 
dataAt(int dataIndex)160   ProfileData dataAt(int dataIndex) {
161     if (outOfBounds(dataIndex)) {
162       return null;
163     }
164     DataLayout dataLayout = new DataLayout(dataField.getValue(getAddress()), dataIndex);
165 
166     switch (dataLayout.tag()) {
167     case DataLayout.noTag:
168     default:
169       throw new InternalError();
170     case DataLayout.bitDataTag:
171       return new BitData(dataLayout);
172     case DataLayout.counterDataTag:
173       return new CounterData(dataLayout);
174     case DataLayout.jumpDataTag:
175       return new JumpData(dataLayout);
176     case DataLayout.receiverTypeDataTag:
177       return new ReceiverTypeData<ciKlass,ciMethod>(this, dataLayout);
178     case DataLayout.virtualCallDataTag:
179       return new VirtualCallData<ciKlass,ciMethod>(this, dataLayout);
180     case DataLayout.retDataTag:
181       return new RetData(dataLayout);
182     case DataLayout.branchDataTag:
183       return new BranchData(dataLayout);
184     case DataLayout.multiBranchDataTag:
185       return new MultiBranchData(dataLayout);
186     case DataLayout.callTypeDataTag:
187       return new CallTypeData<ciKlass,ciMethod>(this, dataLayout);
188     case DataLayout.virtualCallTypeDataTag:
189       return new VirtualCallTypeData<ciKlass,ciMethod>(this, dataLayout);
190     case DataLayout.parametersTypeDataTag:
191       return new ParametersTypeData<ciKlass,ciMethod>(this, dataLayout);
192     }
193   }
194 
dpToDi(int dp)195   int dpToDi(int dp) {
196     return dp;
197   }
198 
firstDi()199   int firstDi() { return 0; }
firstData()200   ProfileData firstData() { return dataAt(firstDi()); }
nextData(ProfileData current)201   ProfileData nextData(ProfileData current) {
202     int currentIndex = dpToDi(current.dp());
203     int nextIndex = currentIndex + current.sizeInBytes();
204     return dataAt(nextIndex);
205   }
isValid(ProfileData current)206   boolean isValid(ProfileData current) { return current != null; }
207 
limitDataPosition()208   DataLayout limitDataPosition() {
209     return new DataLayout(dataField.getValue(getAddress()), dataSize());
210   }
extraDataBase()211   DataLayout extraDataBase() {
212     return limitDataPosition();
213   }
extraDataLimit()214   DataLayout extraDataLimit() {
215     return new DataLayout(dataField.getValue(getAddress()), dataSize() + extraDataSize());
216   }
nextExtra(DataLayout dataLayout)217   DataLayout nextExtra(DataLayout dataLayout) {
218     return new DataLayout(dataField.getValue(getAddress()), dataLayout.dp() + DataLayout.computeSizeInBytes(MethodData.extraNbCells(dataLayout)));
219   }
220 
printDataOn(PrintStream st)221   public void printDataOn(PrintStream st) {
222     if (parametersTypeData() != null) {
223       parametersTypeData().printDataOn(st);
224     }
225     ProfileData data = firstData();
226     for ( ; isValid(data); data = nextData(data)) {
227       st.print(dpToDi(data.dp()));
228       st.print(" ");
229       // st->fillTo(6);
230       data.printDataOn(st);
231     }
232     st.println("--- Extra data:");
233     DataLayout dp    = extraDataBase();
234     DataLayout end   = extraDataLimit();
235     for (;; dp = nextExtra(dp)) {
236       switch(dp.tag()) {
237       case DataLayout.noTag:
238         continue;
239       case DataLayout.bitDataTag:
240         data = new BitData(dp);
241         break;
242       case DataLayout.speculativeTrapDataTag:
243         data = new SpeculativeTrapData<ciKlass,ciMethod>(this, dp);
244         break;
245       case DataLayout.argInfoDataTag:
246         data = new ArgInfoData(dp);
247         dp = end; // ArgInfoData is at the end of extra data section.
248         break;
249       default:
250         throw new InternalError("unexpected tag " +  dp.tag());
251       }
252       st.print(dpToDi(data.dp()));
253       st.print(" ");
254       data.printDataOn(st);
255       if (dp == end) return;
256     }
257   }
258 
dumpReplayDataTypeHelper(PrintStream out, int round, int count, int index, ProfileData pdata, ciKlass k)259   int dumpReplayDataTypeHelper(PrintStream out, int round, int count, int index, ProfileData pdata, ciKlass k) {
260     if (k != null) {
261       if (round == 0) count++;
262       else out.print(" " + ((pdata.dp() + pdata.cellOffset(index)) / MethodData.cellSize) + " " + k.name());
263     }
264     return count;
265   }
266 
dumpReplayDataReceiverTypeHelper(PrintStream out, int round, int count, ReceiverTypeData<ciKlass,ciMethod> vdata)267   int dumpReplayDataReceiverTypeHelper(PrintStream out, int round, int count, ReceiverTypeData<ciKlass,ciMethod> vdata) {
268     for (int i = 0; i < vdata.rowLimit(); i++) {
269       ciKlass k = vdata.receiver(i);
270       count = dumpReplayDataTypeHelper(out, round, count, vdata.receiverCellIndex(i), vdata, k);
271     }
272     return count;
273   }
274 
dumpReplayDataCallTypeHelper(PrintStream out, int round, int count, CallTypeDataInterface<ciKlass> callTypeData)275   int dumpReplayDataCallTypeHelper(PrintStream out, int round, int count, CallTypeDataInterface<ciKlass> callTypeData) {
276     if (callTypeData.hasArguments()) {
277       for (int i = 0; i < callTypeData.numberOfArguments(); i++) {
278         count = dumpReplayDataTypeHelper(out, round, count, callTypeData.argumentTypeIndex(i), (ProfileData)callTypeData, callTypeData.argumentType(i));
279       }
280     }
281     if (callTypeData.hasReturn()) {
282       count = dumpReplayDataTypeHelper(out, round, count, callTypeData.returnTypeIndex(), (ProfileData)callTypeData, callTypeData.returnType());
283     }
284     return count;
285   }
286 
dumpReplayDataExtraDataHelper(PrintStream out, int round, int count)287   int dumpReplayDataExtraDataHelper(PrintStream out, int round, int count) {
288     DataLayout dp    = extraDataBase();
289     DataLayout end   = extraDataLimit();
290 
291     for (;dp != end; dp = nextExtra(dp)) {
292       switch(dp.tag()) {
293       case DataLayout.noTag:
294       case DataLayout.argInfoDataTag:
295         return count;
296       case DataLayout.bitDataTag:
297         break;
298       case DataLayout.speculativeTrapDataTag: {
299         SpeculativeTrapData<ciKlass,ciMethod> data = new SpeculativeTrapData<ciKlass,ciMethod>(this, dp);
300         ciMethod m = data.method();
301         if (m != null) {
302           if (round == 0) {
303             count++;
304           } else {
305             out.print(" " +  (dpToDi(data.dp() + data.cellOffset(SpeculativeTrapData.methodIndex())) / MethodData.cellSize) + " " +  m.nameAsAscii());
306           }
307         }
308         break;
309       }
310       default:
311         throw new InternalError("bad tag "  + dp.tag());
312       }
313     }
314     return count;
315   }
316 
dumpReplayData(PrintStream out)317   public void dumpReplayData(PrintStream out) {
318     MethodData mdo = (MethodData)getMetadata();
319     Method method = mdo.getMethod();
320     out.print("ciMethodData " +
321               method.nameAsAscii() + " " +
322               state() + " " + currentMileage());
323     byte[] orig = orig();
324     out.print(" orig " + orig.length);
325     for (int i = 0; i < orig.length; i++) {
326       out.print(" " + (orig[i] & 0xff));
327     }
328 
329     long[] data = data();
330     out.print(" data " +  data.length);
331     for (int i = 0; i < data.length; i++) {
332       out.print(" 0x" + Long.toHexString(data[i]));
333     }
334     int count = 0;
335     ParametersTypeData<ciKlass,ciMethod> parameters = parametersTypeData();
336     for (int round = 0; round < 2; round++) {
337       if (round == 1) out.print(" oops " + count);
338       ProfileData pdata = firstData();
339       for ( ; isValid(pdata); pdata = nextData(pdata)) {
340         if (pdata instanceof ReceiverTypeData) {
341           @SuppressWarnings("unchecked")
342           ReceiverTypeData<ciKlass,ciMethod> receiverTypeData = (ReceiverTypeData<ciKlass,ciMethod>)pdata;
343           count = dumpReplayDataReceiverTypeHelper(out, round, count, receiverTypeData);
344         }
345         if (pdata instanceof CallTypeDataInterface) {
346           @SuppressWarnings("unchecked")
347           CallTypeDataInterface<ciKlass> callTypeData = (CallTypeDataInterface<ciKlass>)pdata;
348           count = dumpReplayDataCallTypeHelper(out, round, count, callTypeData);
349         }
350       }
351       if (parameters != null) {
352         for (int i = 0; i < parameters.numberOfParameters(); i++) {
353           count = dumpReplayDataTypeHelper(out, round, count, ParametersTypeData.typeIndex(i), parameters, parameters.type(i));
354         }
355       }
356     }
357     count = 0;
358     for (int round = 0; round < 2; round++) {
359       if (round == 1) out.print(" methods " + count);
360       count = dumpReplayDataExtraDataHelper(out, round, count);
361     }
362     out.println();
363   }
364 }
365