Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java @ 6972:bd7a7ce2e264
6830717: replay of compilations would help with debugging
Summary: When java process crashed in compiler thread, repeat the compilation process will help finding root cause. This is done with using SA dump application class data and replay data from core dump, then use debug version of jvm to recompile the problematic java method.
Reviewed-by: kvn, twisti, sspitsyn
Contributed-by: yumin.qi@oracle.com
author | minqi |
---|---|
date | Mon, 12 Nov 2012 14:03:53 -0800 |
parents | da91efe96a93 |
children | 49618582fc5b |
rev | line source |
---|---|
0 | 1 /* |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
2 * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 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 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
36 public class MethodData extends Metadata { |
3939 | 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 | |
0 | 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 { | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
132 Type type = db.lookupType("MethodData"); |
0 | 133 baseOffset = type.getSize(); |
134 | |
135 size = new CIntField(type.getCIntegerField("_size"), 0); | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
136 method = new MetadataField(type.getAddressField("_method"), 0); |
3939 | 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 } | |
0 | 189 } |
190 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
191 public MethodData(Address addr) { |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
192 super(addr); |
0 | 193 } |
194 | |
195 public boolean isMethodData() { return true; } | |
196 | |
197 private static long baseOffset; | |
198 private static CIntField size; | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
199 private static MetadataField method; |
3939 | 200 private static CIntField dataSize; |
201 private static AddressField data; | |
202 | |
203 public static int sizeofMethodDataOopDesc; | |
204 public static int cellSize; | |
0 | 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 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
215 public void iterateFields(MetadataVisitor visitor) { |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
216 super.iterateFields(visitor); |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
217 visitor.doMetadata(method, true); |
0 | 218 visitor.doCInt(size, true); |
219 } | |
3939 | 220 |
221 int dataSize() { | |
222 if (dataSize == null) { | |
223 return 0; | |
224 } else { | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
225 return (int)dataSize.getValue(getAddress()); |
3939 | 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() { | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
295 // fetch the orig MethodData data between header and dataSize |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
296 return fetchDataAt(getAddress(), 0, sizeofMethodDataOopDesc); |
3939 | 297 } |
298 | |
299 public long[] data() { | |
300 // Read the data as an array of intptr_t elements | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3939
diff
changeset
|
301 Address base = getAddress(); |
3939 | 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 } | |
6972
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
335 |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
336 public void dumpReplayData(PrintStream out) { |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
337 Method method = getMethod(); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
338 Klass holder = method.getMethodHolder(); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
339 out.print("ciMethodData " + |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
340 holder.getName().asString() + " " + |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
341 OopUtilities.escapeString(method.getName().asString()) + " " + |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
342 method.getSignature().asString() + " " + |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
343 "2" + " " + |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
344 currentMileage()); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
345 byte[] orig = orig(); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
346 out.print(" orig " + orig.length); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
347 for (int i = 0; i < orig.length; i++) { |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
348 out.print(" " + (orig[i] & 0xff)); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
349 } |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
350 |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
351 long[] data = data(); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
352 out.print(" data " + data.length); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
353 for (int i = 0; i < data.length; i++) { |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
354 out.print(" 0x" + Long.toHexString(data[i])); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
355 } |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
356 int count = 0; |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
357 for (int round = 0; round < 2; round++) { |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
358 if (round == 1) out.print(" oops " + count); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
359 ProfileData pdata = firstData(); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
360 for ( ; isValid(pdata); pdata = nextData(pdata)) { |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
361 if (pdata instanceof ReceiverTypeData) { |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
362 ReceiverTypeData vdata = (ReceiverTypeData)pdata; |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
363 for (int i = 0; i < vdata.rowLimit(); i++) { |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
364 Klass k = vdata.receiver(i); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
365 if (k != null) { |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
366 if (round == 0) count++; |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
367 else out.print(" " + |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
368 (dpToDi(vdata.dp() + |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
369 vdata.cellOffset(vdata.receiverCellIndex(i))) / cellSize) + " " + |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
370 k.getName().asString()); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
371 } |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
372 } |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
373 } else if (pdata instanceof VirtualCallData) { |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
374 VirtualCallData vdata = (VirtualCallData)pdata; |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
375 for (int i = 0; i < vdata.rowLimit(); i++) { |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
376 Klass k = vdata.receiver(i); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
377 if (k != null) { |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
378 if (round == 0) count++; |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
379 else out.print(" " + |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
380 (dpToDi(vdata.dp() + |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
381 vdata.cellOffset(vdata.receiverCellIndex(i))) / cellSize) + " " + |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
382 k.getName().asString()); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
383 } |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
384 } |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
385 } |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
386 } |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
387 } |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
388 out.println(); |
bd7a7ce2e264
6830717: replay of compilations would help with debugging
minqi
parents:
6725
diff
changeset
|
389 } |
0 | 390 } |