View Javadoc
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 {
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.getInvocationCount();
320     long bc = method.getBackedgeCount();
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 }