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)Oop.alignObjectSize(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 ---