Mercurial > hg > graal-jvmci-8
annotate agent/src/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java @ 8059:49618582fc5b
8004840: Jstack seems to output unnecessary information in 7u9
Reviewed-by: dholmes, coleenp, sspitsyn, rbackman
author | sla |
---|---|
date | Thu, 14 Feb 2013 13:08:15 +0100 |
parents | da91efe96a93 |
children |
rev | line source |
---|---|
0 | 1 /* |
6213
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
2 * Copyright (c) 2001, 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.interpreter.*; | |
30 import sun.jvm.hotspot.runtime.*; | |
31 import sun.jvm.hotspot.utilities.*; | |
32 | |
33 /** Minimal port of the VM's oop map generator for interpreted frames */ | |
34 | |
35 public class GenerateOopMap { | |
36 interface JumpClosure { | |
37 public void process(GenerateOopMap c, int bcpDelta, int[] data); | |
38 } | |
39 | |
40 // Used for debugging this code | |
41 private static final boolean DEBUG = false; | |
42 | |
43 // These two should be removed. But requires som code to be cleaned up | |
44 private static final int MAXARGSIZE = 256; // This should be enough | |
45 private static final int MAX_LOCAL_VARS = 65536; // 16-bit entry | |
46 private static final boolean TraceMonitorMismatch = true; | |
47 private static final boolean TraceOopMapRewrites = true; | |
48 | |
49 // Commonly used constants | |
50 static CellTypeState[] epsilonCTS = { CellTypeState.bottom }; | |
51 static CellTypeState refCTS = CellTypeState.ref; | |
52 static CellTypeState valCTS = CellTypeState.value; | |
53 static CellTypeState[] vCTS = { CellTypeState.value, CellTypeState.bottom }; | |
54 static CellTypeState[] rCTS = { CellTypeState.ref, CellTypeState.bottom }; | |
55 static CellTypeState[] rrCTS = { CellTypeState.ref, CellTypeState.ref, CellTypeState.bottom }; | |
56 static CellTypeState[] vrCTS = { CellTypeState.value, CellTypeState.ref, CellTypeState.bottom }; | |
57 static CellTypeState[] vvCTS = { CellTypeState.value, CellTypeState.value, CellTypeState.bottom }; | |
58 static CellTypeState[] rvrCTS = { CellTypeState.ref, CellTypeState.value, CellTypeState.ref, CellTypeState.bottom }; | |
59 static CellTypeState[] vvrCTS = { CellTypeState.value, CellTypeState.value, CellTypeState.ref, CellTypeState.bottom }; | |
60 static CellTypeState[] vvvCTS = { CellTypeState.value, CellTypeState.value, CellTypeState.value, CellTypeState.bottom }; | |
61 static CellTypeState[] vvvrCTS = { CellTypeState.value, CellTypeState.value, CellTypeState.value, CellTypeState.ref, CellTypeState.bottom }; | |
62 static CellTypeState[] vvvvCTS = { CellTypeState.value, CellTypeState.value, CellTypeState.value, CellTypeState.value, CellTypeState.bottom }; | |
63 | |
64 /** Specialization of SignatureIterator - compute the effects of a call */ | |
65 static class ComputeCallStack extends SignatureIterator { | |
66 CellTypeStateList _effect; | |
67 int _idx; | |
68 | |
69 void set(CellTypeState state) { _effect.get(_idx++).set(state); } | |
70 int length() { return _idx; }; | |
71 | |
72 public void doBool () { set(CellTypeState.value); } | |
73 public void doChar () { set(CellTypeState.value); } | |
74 public void doFloat () { set(CellTypeState.value); } | |
75 public void doByte () { set(CellTypeState.value); } | |
76 public void doShort () { set(CellTypeState.value); } | |
77 public void doInt () { set(CellTypeState.value); } | |
78 public void doVoid () { set(CellTypeState.bottom);} | |
79 public void doObject(int begin, int end) { set(CellTypeState.ref); } | |
80 public void doArray (int begin, int end) { set(CellTypeState.ref); } | |
81 | |
82 public void doDouble() { set(CellTypeState.value); | |
83 set(CellTypeState.value); } | |
84 public void doLong () { set(CellTypeState.value); | |
85 set(CellTypeState.value); } | |
86 | |
87 ComputeCallStack(Symbol signature) { | |
88 super(signature); | |
89 } | |
90 | |
91 // Compute methods | |
92 int computeForParameters(boolean is_static, CellTypeStateList effect) { | |
93 _idx = 0; | |
94 _effect = effect; | |
95 | |
96 if (!is_static) { | |
97 effect.get(_idx++).set(CellTypeState.ref); | |
98 } | |
99 | |
100 iterateParameters(); | |
101 | |
102 return length(); | |
103 }; | |
104 | |
105 int computeForReturntype(CellTypeStateList effect) { | |
106 _idx = 0; | |
107 _effect = effect; | |
108 iterateReturntype(); | |
109 set(CellTypeState.bottom); // Always terminate with a bottom state, so ppush works | |
110 | |
111 return length(); | |
112 } | |
113 } | |
114 | |
115 /** Specialization of SignatureIterator - in order to set up first stack frame */ | |
116 static class ComputeEntryStack extends SignatureIterator { | |
117 CellTypeStateList _effect; | |
118 int _idx; | |
119 | |
120 void set(CellTypeState state) { _effect.get(_idx++).set(state); } | |
121 int length() { return _idx; }; | |
122 | |
123 public void doBool () { set(CellTypeState.value); } | |
124 public void doChar () { set(CellTypeState.value); } | |
125 public void doFloat () { set(CellTypeState.value); } | |
126 public void doByte () { set(CellTypeState.value); } | |
127 public void doShort () { set(CellTypeState.value); } | |
128 public void doInt () { set(CellTypeState.value); } | |
129 public void doVoid () { set(CellTypeState.bottom);} | |
130 public void doObject(int begin, int end) { set(CellTypeState.makeSlotRef(_idx)); } | |
131 public void doArray (int begin, int end) { set(CellTypeState.makeSlotRef(_idx)); } | |
132 | |
133 public void doDouble() { set(CellTypeState.value); | |
134 set(CellTypeState.value); } | |
135 public void doLong () { set(CellTypeState.value); | |
136 set(CellTypeState.value); } | |
137 | |
138 ComputeEntryStack(Symbol signature) { | |
139 super(signature); | |
140 } | |
141 | |
142 // Compute methods | |
143 int computeForParameters(boolean is_static, CellTypeStateList effect) { | |
144 _idx = 0; | |
145 _effect = effect; | |
146 | |
147 if (!is_static) { | |
148 effect.get(_idx++).set(CellTypeState.makeSlotRef(0)); | |
149 } | |
150 | |
151 iterateParameters(); | |
152 | |
153 return length(); | |
154 }; | |
155 | |
156 int computeForReturntype(CellTypeStateList effect) { | |
157 _idx = 0; | |
158 _effect = effect; | |
159 iterateReturntype(); | |
160 set(CellTypeState.bottom); // Always terminate with a bottom state, so ppush works | |
161 | |
162 return length(); | |
163 } | |
164 } | |
165 | |
166 /** Contains maping between jsr targets and there return addresses. | |
167 One-to-many mapping. */ | |
168 static class RetTableEntry { | |
169 private static int _init_nof_jsrs; // Default size of jsrs list | |
170 private int _target_bci; // Target PC address of jump (bytecode index) | |
171 private List/*<int>*/ _jsrs; // List of return addresses (bytecode index) | |
172 private RetTableEntry _next; // Link to next entry | |
173 | |
174 RetTableEntry(int target, RetTableEntry next) { | |
175 _target_bci = target; | |
176 _jsrs = new ArrayList(_init_nof_jsrs); | |
177 _next = next; | |
178 } | |
179 | |
180 // Query | |
181 int targetBci() { return _target_bci; } | |
182 int nofJsrs() { return _jsrs.size(); } | |
183 int jsrs(int i) { return ((Integer) _jsrs.get(i)).intValue(); } | |
184 | |
185 // Update entry | |
186 void addJsr (int return_bci) { _jsrs.add(new Integer(return_bci)); } | |
187 void addDelta(int bci, int delta) { | |
188 if (_target_bci > bci) { | |
189 _target_bci += delta; | |
190 } | |
191 | |
192 for (int k = 0; k < nofJsrs(); k++) { | |
193 int jsr = jsrs(k); | |
194 if (jsr > bci) { | |
195 _jsrs.set(k, new Integer(jsr+delta)); | |
196 } | |
197 } | |
198 } | |
199 RetTableEntry next() { return _next; } | |
200 } | |
201 | |
202 static class RetTable { | |
203 private RetTableEntry _first; | |
204 private static int _init_nof_entries; | |
205 | |
206 private void addJsr(int return_bci, int target_bci) { | |
207 RetTableEntry entry = _first; | |
208 | |
209 // Scan table for entry | |
210 for (;(entry != null) && (entry.targetBci() != target_bci); entry = entry.next()); | |
211 | |
212 if (entry == null) { | |
213 // Allocate new entry and put in list | |
214 entry = new RetTableEntry(target_bci, _first); | |
215 _first = entry; | |
216 } | |
217 | |
218 // Now "entry" is set. Make sure that the entry is initialized | |
219 // and has room for the new jsr. | |
220 entry.addJsr(return_bci); | |
221 } | |
222 | |
223 RetTable() {} | |
224 void computeRetTable(Method method) { | |
225 BytecodeStream i = new BytecodeStream(method); | |
226 int bytecode; | |
227 | |
228 while( (bytecode = i.next()) >= 0) { | |
229 switch (bytecode) { | |
230 case Bytecodes._jsr: | |
231 addJsr(i.nextBCI(), i.dest()); | |
232 break; | |
233 case Bytecodes._jsr_w: | |
234 addJsr(i.nextBCI(), i.dest_w()); | |
235 break; | |
236 } | |
237 } | |
238 } | |
239 void updateRetTable(int bci, int delta) { | |
240 RetTableEntry cur = _first; | |
241 while(cur != null) { | |
242 cur.addDelta(bci, delta); | |
243 cur = cur.next(); | |
244 } | |
245 } | |
246 RetTableEntry findJsrsForTarget(int targBci) { | |
247 RetTableEntry cur = _first; | |
248 | |
249 while(cur != null) { | |
250 if (Assert.ASSERTS_ENABLED) { | |
251 Assert.that(cur.targetBci() != -1, "sanity check"); | |
252 } | |
253 if (cur.targetBci() == targBci) { | |
254 return cur; | |
255 } | |
256 cur = cur.next(); | |
257 } | |
258 throw new RuntimeException("Should not reach here"); | |
259 } | |
260 } | |
261 | |
262 static class BasicBlock { | |
263 private boolean _changed; // Reached a fixpoint or not | |
264 static final int _dead_basic_block = -2; | |
265 // Alive but not yet reached by analysis | |
266 static final int _unreached = -1; | |
267 // >=0: Alive and has a merged state | |
268 | |
269 int _bci; // Start of basic block | |
270 int _end_bci; // Bci of last instruction in basicblock | |
271 int _max_locals; // Determines split between vars and stack | |
272 int _max_stack; // Determines split between stack and monitors | |
273 CellTypeStateList _state; // State (vars, stack) at entry. | |
274 int _stack_top; // -1 indicates bottom stack value. | |
275 int _monitor_top; // -1 indicates bottom monitor stack value. | |
276 | |
277 CellTypeStateList vars() { return _state; } | |
278 CellTypeStateList stack() { return _state.subList(_max_locals, _state.size()); } | |
279 | |
280 boolean changed() { return _changed; } | |
281 void setChanged(boolean s) { _changed = s; } | |
282 | |
283 // Analysis has reached this basicblock | |
284 boolean isReachable() { return _stack_top >= 0; } | |
285 | |
286 // All basicblocks that are unreachable are going to have a _stack_top == _dead_basic_block. | |
287 // This info. is setup in a pre-parse before the real abstract interpretation starts. | |
288 boolean isDead() { return _stack_top == _dead_basic_block; } | |
289 boolean isAlive() { return _stack_top != _dead_basic_block; } | |
290 void markAsAlive() { | |
291 if (Assert.ASSERTS_ENABLED) { | |
292 Assert.that(isDead(), "must be dead"); | |
293 _stack_top = _unreached; | |
294 } | |
295 } | |
296 } | |
297 | |
298 //---------------------------------------------------------------------- | |
299 // Protected routines for GenerateOopMap | |
300 // | |
301 | |
302 // _monitor_top is set to this constant to indicate that a monitor matching | |
303 // problem was encountered prior to this point in control flow. | |
304 protected static final int bad_monitors = -1; | |
305 | |
306 // Main variables | |
307 Method _method; // The method we are examining | |
308 RetTable _rt; // Contains the return address mappings | |
309 int _max_locals; // Cached value of no. of locals | |
310 int _max_stack; // Cached value of max. stack depth | |
311 int _max_monitors; // Cached value of max. monitor stack depth | |
312 boolean _has_exceptions; // True, if exceptions exist for method | |
313 boolean _got_error; // True, if an error occured during interpretation. | |
314 String _error_msg; // Error message. Set if _got_error is true. | |
315 // bool _did_rewriting; // was bytecodes rewritten | |
316 // bool _did_relocation; // was relocation neccessary | |
317 boolean _monitor_safe; // The monitors in this method have been determined | |
318 // to be safe. | |
319 | |
320 // Working Cell type state | |
321 int _state_len; // Size of states | |
322 CellTypeStateList _state; // list of states | |
323 char[] _state_vec_buf; // Buffer used to print a readable version of a state | |
324 int _stack_top; | |
325 int _monitor_top; | |
326 | |
327 // Timing and statistics | |
328 // static elapsedTimer _total_oopmap_time; // Holds cumulative oopmap generation time | |
329 // static long _total_byte_count; // Holds cumulative number of bytes inspected | |
330 | |
331 // Monitor query logic | |
332 int _report_for_exit_bci; | |
333 int _matching_enter_bci; | |
334 | |
335 // Cell type methods | |
336 void initState() { | |
337 _state_len = _max_locals + _max_stack + _max_monitors; | |
338 _state = new CellTypeStateList(_state_len); | |
339 _state_vec_buf = new char[Math.max(_max_locals, Math.max(_max_stack, Math.max(_max_monitors, 1)))]; | |
340 } | |
341 void makeContextUninitialized () { | |
342 CellTypeStateList vs = vars(); | |
343 | |
344 for (int i = 0; i < _max_locals; i++) | |
345 vs.get(i).set(CellTypeState.uninit); | |
346 | |
347 _stack_top = 0; | |
348 _monitor_top = 0; | |
349 } | |
350 | |
351 int methodsigToEffect (Symbol signature, boolean isStatic, CellTypeStateList effect) { | |
352 ComputeEntryStack ces = new ComputeEntryStack(signature); | |
353 return ces.computeForParameters(isStatic, effect); | |
354 } | |
355 | |
356 boolean mergeStateVectors (CellTypeStateList cts, CellTypeStateList bbts) { | |
357 int i; | |
358 int len = _max_locals + _stack_top; | |
359 boolean change = false; | |
360 | |
361 for (i = len - 1; i >= 0; i--) { | |
362 CellTypeState v = cts.get(i).merge(bbts.get(i), i); | |
363 change = change || !v.equal(bbts.get(i)); | |
364 bbts.get(i).set(v); | |
365 } | |
366 | |
367 if (_max_monitors > 0 && _monitor_top != bad_monitors) { | |
368 // If there are no monitors in the program, or there has been | |
369 // a monitor matching error before this point in the program, | |
370 // then we do not merge in the monitor state. | |
371 | |
372 int base = _max_locals + _max_stack; | |
373 len = base + _monitor_top; | |
374 for (i = len - 1; i >= base; i--) { | |
375 CellTypeState v = cts.get(i).merge(bbts.get(i), i); | |
376 | |
377 // Can we prove that, when there has been a change, it will already | |
378 // have been detected at this point? That would make this equal | |
379 // check here unnecessary. | |
380 change = change || !v.equal(bbts.get(i)); | |
381 bbts.get(i).set(v); | |
382 } | |
383 } | |
384 | |
385 return change; | |
386 } | |
387 | |
388 void copyState (CellTypeStateList dst, CellTypeStateList src) { | |
389 int len = _max_locals + _stack_top; | |
390 for (int i = 0; i < len; i++) { | |
391 if (src.get(i).isNonlockReference()) { | |
392 dst.get(i).set(CellTypeState.makeSlotRef(i)); | |
393 } else { | |
394 dst.get(i).set(src.get(i)); | |
395 } | |
396 } | |
397 if (_max_monitors > 0 && _monitor_top != bad_monitors) { | |
398 int base = _max_locals + _max_stack; | |
399 len = base + _monitor_top; | |
400 for (int i = base; i < len; i++) { | |
401 dst.get(i).set(src.get(i)); | |
402 } | |
403 } | |
404 } | |
405 | |
406 void mergeStateIntoBB (BasicBlock bb) { | |
407 if (Assert.ASSERTS_ENABLED) { | |
408 Assert.that(bb.isAlive(), "merging state into a dead basicblock"); | |
409 } | |
410 | |
411 if (_stack_top == bb._stack_top) { | |
412 if (_monitor_top == bb._monitor_top) { | |
413 if (mergeStateVectors(_state, bb._state)) { | |
414 bb.setChanged(true); | |
415 } | |
416 } else { | |
417 if (TraceMonitorMismatch) { | |
418 reportMonitorMismatch("monitor stack height merge conflict"); | |
419 } | |
420 // When the monitor stacks are not matched, we set _monitor_top to | |
421 // bad_monitors. This signals that, from here on, the monitor stack cannot | |
422 // be trusted. In particular, monitorexit bytecodes may throw | |
423 // exceptions. We mark this block as changed so that the change | |
424 // propagates properly. | |
425 bb._monitor_top = bad_monitors; | |
426 bb.setChanged(true); | |
427 _monitor_safe = false; | |
428 } | |
429 } else if (!bb.isReachable()) { | |
430 // First time we look at this BB | |
431 copyState(bb._state, _state); | |
432 bb._stack_top = _stack_top; | |
433 bb._monitor_top = _monitor_top; | |
434 bb.setChanged(true); | |
435 } else { | |
436 throw new RuntimeException("stack height conflict: " + | |
437 _stack_top + " vs. " + bb._stack_top); | |
438 } | |
439 } | |
440 | |
441 void mergeState (int bci, int[] data) { | |
442 mergeStateIntoBB(getBasicBlockAt(bci)); | |
443 } | |
444 | |
445 void setVar (int localNo, CellTypeState cts) { | |
446 if (Assert.ASSERTS_ENABLED) { | |
447 Assert.that(cts.isReference() || cts.isValue() || cts.isAddress(), | |
448 "wrong celltypestate"); | |
449 } | |
450 if (localNo < 0 || localNo > _max_locals) { | |
451 throw new RuntimeException("variable write error: r" + localNo); | |
452 } | |
453 vars().get(localNo).set(cts); | |
454 } | |
455 | |
456 CellTypeState getVar (int localNo) { | |
457 if (Assert.ASSERTS_ENABLED) { | |
458 Assert.that(localNo < _max_locals + _nof_refval_conflicts, "variable read error"); | |
459 } | |
460 if (localNo < 0 || localNo > _max_locals) { | |
461 throw new RuntimeException("variable read error: r" + localNo); | |
462 } | |
463 return vars().get(localNo).copy(); | |
464 } | |
465 | |
466 CellTypeState pop () { | |
467 if ( _stack_top <= 0) { | |
468 throw new RuntimeException("stack underflow"); | |
469 } | |
470 return stack().get(--_stack_top).copy(); | |
471 } | |
472 | |
473 void push (CellTypeState cts) { | |
474 if ( _stack_top >= _max_stack) { | |
475 if (DEBUG) { | |
476 System.err.println("Method: " + method().getName().asString() + method().getSignature().asString() + | |
477 " _stack_top: " + _stack_top + " _max_stack: " + _max_stack); | |
478 } | |
479 throw new RuntimeException("stack overflow"); | |
480 } | |
481 stack().get(_stack_top++).set(cts); | |
482 if (DEBUG) { | |
483 System.err.println("After push: _stack_top: " + _stack_top + | |
484 " _max_stack: " + _max_stack + | |
485 " just pushed: " + cts.toChar()); | |
486 } | |
487 } | |
488 | |
489 CellTypeState monitorPop () { | |
490 if (Assert.ASSERTS_ENABLED) { | |
491 Assert.that(_monitor_top != bad_monitors, "monitorPop called on error monitor stack"); | |
492 } | |
493 if (_monitor_top == 0) { | |
494 // We have detected a pop of an empty monitor stack. | |
495 _monitor_safe = false; | |
496 _monitor_top = bad_monitors; | |
497 | |
498 if (TraceMonitorMismatch) { | |
499 reportMonitorMismatch("monitor stack underflow"); | |
500 } | |
501 return CellTypeState.ref; // just to keep the analysis going. | |
502 } | |
503 return monitors().get(--_monitor_top).copy(); | |
504 } | |
505 | |
506 void monitorPush (CellTypeState cts) { | |
507 if (Assert.ASSERTS_ENABLED) { | |
508 Assert.that(_monitor_top != bad_monitors, "monitorPush called on error monitor stack"); | |
509 } | |
510 if (_monitor_top >= _max_monitors) { | |
511 // Some monitorenter is being executed more than once. | |
512 // This means that the monitor stack cannot be simulated. | |
513 _monitor_safe = false; | |
514 _monitor_top = bad_monitors; | |
515 | |
516 if (TraceMonitorMismatch) { | |
517 reportMonitorMismatch("monitor stack overflow"); | |
518 } | |
519 return; | |
520 } | |
521 monitors().get(_monitor_top++).set(cts); | |
522 } | |
523 | |
524 CellTypeStateList vars () { return _state; } | |
525 CellTypeStateList stack () { return _state.subList(_max_locals, _state.size()); } | |
526 CellTypeStateList monitors() { return _state.subList(_max_locals+_max_stack, _state.size()); } | |
527 | |
528 void replaceAllCTSMatches (CellTypeState match, | |
529 CellTypeState replace) { | |
530 int i; | |
531 int len = _max_locals + _stack_top; | |
532 boolean change = false; | |
533 | |
534 for (i = len - 1; i >= 0; i--) { | |
535 if (match.equal(_state.get(i))) { | |
536 _state.get(i).set(replace); | |
537 } | |
538 } | |
539 | |
540 if (_monitor_top > 0) { | |
541 int base = _max_locals + _max_stack; | |
542 len = base + _monitor_top; | |
543 for (i = len - 1; i >= base; i--) { | |
544 if (match.equal(_state.get(i))) { | |
545 _state.get(i).set(replace); | |
546 } | |
547 } | |
548 } | |
549 } | |
550 | |
551 void printStates (PrintStream tty, CellTypeStateList vector, int num) { | |
552 for (int i = 0; i < num; i++) { | |
553 vector.get(i).print(tty); | |
554 } | |
555 } | |
556 | |
557 void printCurrentState (PrintStream tty, | |
558 BytecodeStream currentBC, | |
559 boolean detailed) { | |
560 if (detailed) { | |
561 tty.print(" " + currentBC.bci() + " vars = "); | |
562 printStates(tty, vars(), _max_locals); | |
563 tty.print(" " + Bytecodes.name(currentBC.code())); | |
564 switch(currentBC.code()) { | |
565 case Bytecodes._invokevirtual: | |
566 case Bytecodes._invokespecial: | |
567 case Bytecodes._invokestatic: | |
568 case Bytecodes._invokeinterface: | |
1602 | 569 case Bytecodes._invokedynamic: |
0 | 570 // FIXME: print signature of referenced method (need more |
571 // accessors in ConstantPool and ConstantPoolCache) | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
572 int idx = currentBC.hasIndexU4() ? currentBC.getIndexU4() : currentBC.getIndexU2(); |
0 | 573 tty.print(" idx " + idx); |
574 /* | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
575 int idx = currentBC.getIndexU2(); |
0 | 576 ConstantPool cp = method().getConstants(); |
577 int nameAndTypeIdx = cp.name_and_type_ref_index_at(idx); | |
578 int signatureIdx = cp.signature_ref_index_at(nameAndTypeIdx); | |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
2042
diff
changeset
|
579 Symbol* signature = cp.symbol_at(signatureIdx); |
0 | 580 tty.print("%s", signature.as_C_string()); |
581 */ | |
582 } | |
583 tty.println(); | |
584 tty.print(" stack = "); | |
585 printStates(tty, stack(), _stack_top); | |
586 tty.println(); | |
587 if (_monitor_top != bad_monitors) { | |
588 tty.print(" monitors = "); | |
589 printStates(tty, monitors(), _monitor_top); | |
590 } else { | |
591 tty.print(" [bad monitor stack]"); | |
592 } | |
593 tty.println(); | |
594 } else { | |
595 tty.print(" " + currentBC.bci() + " vars = '" + | |
596 stateVecToString(vars(), _max_locals) + "' "); | |
597 tty.print(" stack = '" + stateVecToString(stack(), _stack_top) + "' "); | |
598 if (_monitor_top != bad_monitors) { | |
599 tty.print(" monitors = '" + stateVecToString(monitors(), _monitor_top) + "' \t" + | |
600 Bytecodes.name(currentBC.code())); | |
601 } else { | |
602 tty.print(" [bad monitor stack]"); | |
603 } | |
604 switch(currentBC.code()) { | |
605 case Bytecodes._invokevirtual: | |
606 case Bytecodes._invokespecial: | |
607 case Bytecodes._invokestatic: | |
608 case Bytecodes._invokeinterface: | |
1602 | 609 case Bytecodes._invokedynamic: |
0 | 610 // FIXME: print signature of referenced method (need more |
611 // accessors in ConstantPool and ConstantPoolCache) | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
612 int idx = currentBC.hasIndexU4() ? currentBC.getIndexU4() : currentBC.getIndexU2(); |
0 | 613 tty.print(" idx " + idx); |
614 /* | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
615 int idx = currentBC.getIndexU2(); |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6213
diff
changeset
|
616 ConstantPool* cp = method().constants(); |
0 | 617 int nameAndTypeIdx = cp.name_and_type_ref_index_at(idx); |
618 int signatureIdx = cp.signature_ref_index_at(nameAndTypeIdx); | |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
2042
diff
changeset
|
619 Symbol* signature = cp.symbol_at(signatureIdx); |
0 | 620 tty.print("%s", signature.as_C_string()); |
621 */ | |
622 } | |
623 tty.println(); | |
624 } | |
625 } | |
626 | |
627 void reportMonitorMismatch (String msg) { | |
628 if (Assert.ASSERTS_ENABLED) { | |
629 System.err.print(" Monitor mismatch in method "); | |
630 method().printValueOn(System.err); | |
631 System.err.println(": " + msg); | |
632 } | |
633 } | |
634 | |
635 // Basicblock info | |
636 BasicBlock[] _basic_blocks; // Array of basicblock info | |
637 int _gc_points; | |
638 int _bb_count; | |
639 BitMap _bb_hdr_bits; | |
640 | |
641 // Basicblocks methods | |
642 void initializeBB () { | |
643 _gc_points = 0; | |
644 _bb_count = 0; | |
645 _bb_hdr_bits = new BitMap((int) _method.getCodeSize()); | |
646 } | |
647 | |
648 void markBBHeadersAndCountGCPoints() { | |
649 initializeBB(); | |
650 | |
651 boolean fellThrough = false; // False to get first BB marked. | |
652 | |
653 // First mark all exception handlers as start of a basic-block | |
6213
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
654 if (method().hasExceptionTable()) { |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
655 ExceptionTableElement[] excps = method().getExceptionTable(); |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
656 for(int i = 0; i < excps.length; i++) { |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
657 markBB(excps[i].getHandlerPC(), null); |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
658 } |
0 | 659 } |
660 | |
661 // Then iterate through the code | |
662 BytecodeStream bcs = new BytecodeStream(_method); | |
663 int bytecode; | |
664 | |
665 while( (bytecode = bcs.next()) >= 0) { | |
666 int bci = bcs.bci(); | |
667 | |
668 if (!fellThrough) | |
669 markBB(bci, null); | |
670 | |
671 fellThrough = jumpTargetsDo(bcs, | |
672 new JumpClosure() { | |
673 public void process(GenerateOopMap c, int bcpDelta, int[] data) { | |
674 c.markBB(bcpDelta, data); | |
675 } | |
676 }, | |
677 null); | |
678 | |
679 /* We will also mark successors of jsr's as basic block headers. */ | |
680 switch (bytecode) { | |
681 case Bytecodes._jsr: | |
682 if (Assert.ASSERTS_ENABLED) { | |
683 Assert.that(!fellThrough, "should not happen"); | |
684 } | |
685 markBB(bci + Bytecodes.lengthFor(bytecode), null); | |
686 break; | |
687 case Bytecodes._jsr_w: | |
688 if (Assert.ASSERTS_ENABLED) { | |
689 Assert.that(!fellThrough, "should not happen"); | |
690 } | |
691 markBB(bci + Bytecodes.lengthFor(bytecode), null); | |
692 break; | |
693 } | |
694 | |
695 if (possibleGCPoint(bcs)) | |
696 _gc_points++; | |
697 } | |
698 } | |
699 | |
700 boolean isBBHeader (int bci) { | |
701 return _bb_hdr_bits.at(bci); | |
702 } | |
703 | |
704 int gcPoints () { | |
705 return _gc_points; | |
706 } | |
707 | |
708 int bbCount () { | |
709 return _bb_count; | |
710 } | |
711 | |
712 void setBBMarkBit (int bci) { | |
713 _bb_hdr_bits.atPut(bci, true); | |
714 } | |
715 | |
716 void clear_bbmark_bit (int bci) { | |
717 _bb_hdr_bits.atPut(bci, false); | |
718 } | |
719 | |
720 BasicBlock getBasicBlockAt (int bci) { | |
721 BasicBlock bb = getBasicBlockContaining(bci); | |
722 if (Assert.ASSERTS_ENABLED) { | |
723 Assert.that(bb._bci == bci, "should have found BB"); | |
724 } | |
725 return bb; | |
726 } | |
727 | |
728 BasicBlock getBasicBlockContaining (int bci) { | |
729 BasicBlock[] bbs = _basic_blocks; | |
730 int lo = 0, hi = _bb_count - 1; | |
731 | |
732 while (lo <= hi) { | |
733 int m = (lo + hi) / 2; | |
734 int mbci = bbs[m]._bci; | |
735 int nbci; | |
736 | |
737 if ( m == _bb_count-1) { | |
738 if (Assert.ASSERTS_ENABLED) { | |
739 Assert.that( bci >= mbci && bci < method().getCodeSize(), "sanity check failed"); | |
740 } | |
741 return bbs[m]; | |
742 } else { | |
743 nbci = bbs[m+1]._bci; | |
744 } | |
745 | |
746 if ( mbci <= bci && bci < nbci) { | |
747 return bbs[m]; | |
748 } else if (mbci < bci) { | |
749 lo = m + 1; | |
750 } else { | |
751 if (Assert.ASSERTS_ENABLED) { | |
752 Assert.that(mbci > bci, "sanity check"); | |
753 } | |
754 hi = m - 1; | |
755 } | |
756 } | |
757 | |
758 throw new RuntimeException("should have found BB"); | |
759 } | |
760 | |
761 void interpBB (BasicBlock bb) { | |
762 // We do not want to do anything in case the basic-block has not been initialized. This | |
763 // will happen in the case where there is dead-code hang around in a method. | |
764 if (Assert.ASSERTS_ENABLED) { | |
765 Assert.that(bb.isReachable(), "should be reachable or deadcode exist"); | |
766 } | |
767 restoreState(bb); | |
768 | |
769 BytecodeStream itr = new BytecodeStream(_method); | |
770 | |
771 // Set iterator interval to be the current basicblock | |
772 int lim_bci = nextBBStartPC(bb); | |
773 itr.setInterval(bb._bci, lim_bci); | |
774 | |
775 if (DEBUG) { | |
776 System.err.println("interpBB: method = " + method().getName().asString() + | |
777 method().getSignature().asString() + | |
778 ", BCI interval [" + bb._bci + ", " + lim_bci + ")"); | |
779 { | |
780 System.err.print("Bytecodes:"); | |
781 for (int i = bb._bci; i < lim_bci; i++) { | |
782 System.err.print(" 0x" + Long.toHexString(method().getBytecodeOrBPAt(i))); | |
783 } | |
784 System.err.println(); | |
785 } | |
786 } | |
787 | |
788 if (Assert.ASSERTS_ENABLED) { | |
789 Assert.that(lim_bci != bb._bci, "must be at least one instruction in a basicblock"); | |
790 } | |
791 itr.next(); // read first instruction | |
792 | |
793 // Iterates through all bytecodes except the last in a basic block. | |
794 // We handle the last one special, since there is controlflow change. | |
795 while(itr.nextBCI() < lim_bci && !_got_error) { | |
796 if (_has_exceptions || (_monitor_top != 0)) { | |
797 // We do not need to interpret the results of exceptional | |
798 // continuation from this instruction when the method has no | |
799 // exception handlers and the monitor stack is currently | |
800 // empty. | |
801 doExceptionEdge(itr); | |
802 } | |
803 interp1(itr); | |
804 itr.next(); | |
805 } | |
806 | |
807 // Handle last instruction. | |
808 if (!_got_error) { | |
809 if (Assert.ASSERTS_ENABLED) { | |
810 Assert.that(itr.nextBCI() == lim_bci, "must point to end"); | |
811 } | |
812 if (_has_exceptions || (_monitor_top != 0)) { | |
813 doExceptionEdge(itr); | |
814 } | |
815 interp1(itr); | |
816 | |
817 boolean fall_through = jumpTargetsDo(itr, new JumpClosure() { | |
818 public void process(GenerateOopMap c, int bcpDelta, int[] data) { | |
819 c.mergeState(bcpDelta, data); | |
820 } | |
821 }, null); | |
822 if (_got_error) return; | |
823 | |
824 if (itr.code() == Bytecodes._ret) { | |
825 if (Assert.ASSERTS_ENABLED) { | |
826 Assert.that(!fall_through, "cannot be set if ret instruction"); | |
827 } | |
828 // Automatically handles 'wide' ret indicies | |
829 retJumpTargetsDo(itr, new JumpClosure() { | |
830 public void process(GenerateOopMap c, int bcpDelta, int[] data) { | |
831 c.mergeState(bcpDelta, data); | |
832 } | |
833 }, itr.getIndex(), null); | |
834 } else if (fall_through) { | |
835 // Hit end of BB, but the instr. was a fall-through instruction, | |
836 // so perform transition as if the BB ended in a "jump". | |
837 if (Assert.ASSERTS_ENABLED) { | |
838 Assert.that(lim_bci == _basic_blocks[bbIndex(bb) + 1]._bci, "there must be another bb"); | |
839 } | |
840 mergeStateIntoBB(_basic_blocks[bbIndex(bb) + 1]); | |
841 } | |
842 } | |
843 } | |
844 | |
845 void restoreState (BasicBlock bb) { | |
846 for (int i = 0; i < _state_len; i++) { | |
847 _state.get(i).set(bb._state.get(i)); | |
848 } | |
849 _stack_top = bb._stack_top; | |
850 _monitor_top = bb._monitor_top; | |
851 } | |
852 | |
853 int nextBBStartPC (BasicBlock bb) { | |
854 int bbNum = bbIndex(bb) + 1; | |
855 if (bbNum == _bb_count) | |
856 return (int) method().getCodeSize(); | |
857 | |
858 return _basic_blocks[bbNum]._bci; | |
859 } | |
860 | |
861 void updateBasicBlocks (int bci, int delta) { | |
862 BitMap bbBits = new BitMap((int) (_method.getCodeSize() + delta)); | |
863 for(int k = 0; k < _bb_count; k++) { | |
864 if (_basic_blocks[k]._bci > bci) { | |
865 _basic_blocks[k]._bci += delta; | |
866 _basic_blocks[k]._end_bci += delta; | |
867 } | |
868 bbBits.atPut(_basic_blocks[k]._bci, true); | |
869 } | |
870 _bb_hdr_bits = bbBits; | |
871 } | |
872 | |
873 void markBB(int bci, int[] data) { | |
874 if (Assert.ASSERTS_ENABLED) { | |
875 Assert.that(bci>= 0 && bci < method().getCodeSize(), "index out of bounds"); | |
876 } | |
877 if (isBBHeader(bci)) | |
878 return; | |
879 | |
880 // FIXME: remove | |
881 // if (TraceNewOopMapGeneration) { | |
882 // tty.print_cr("Basicblock#%d begins at: %d", c._bb_count, bci); | |
883 // } | |
884 setBBMarkBit(bci); | |
885 _bb_count++; | |
886 } | |
887 | |
888 // Dead code detection | |
889 void markReachableCode() { | |
890 final int[] change = new int[1]; | |
891 change[0] = 1; | |
892 | |
893 // Mark entry basic block as alive and all exception handlers | |
894 _basic_blocks[0].markAsAlive(); | |
6213
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
895 if (method().hasExceptionTable()) { |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
896 ExceptionTableElement[] excps = method().getExceptionTable(); |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
897 for(int i = 0; i < excps.length; i ++) { |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
898 BasicBlock bb = getBasicBlockAt(excps[i].getHandlerPC()); |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
899 // If block is not already alive (due to multiple exception handlers to same bb), then |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
900 // make it alive |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
901 if (bb.isDead()) |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
902 bb.markAsAlive(); |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
903 } |
0 | 904 } |
905 | |
906 BytecodeStream bcs = new BytecodeStream(_method); | |
907 | |
908 // Iterate through all basic blocks until we reach a fixpoint | |
909 while (change[0] != 0) { | |
910 change[0] = 0; | |
911 | |
912 for (int i = 0; i < _bb_count; i++) { | |
913 BasicBlock bb = _basic_blocks[i]; | |
914 if (bb.isAlive()) { | |
915 // Position bytecodestream at last bytecode in basicblock | |
916 bcs.setStart(bb._end_bci); | |
917 bcs.next(); | |
918 int bytecode = bcs.code(); | |
919 int bci = bcs.bci(); | |
920 if (Assert.ASSERTS_ENABLED) { | |
921 Assert.that(bci == bb._end_bci, "wrong bci"); | |
922 } | |
923 | |
924 boolean fell_through = jumpTargetsDo(bcs, new JumpClosure() { | |
925 public void process(GenerateOopMap c, int bciDelta, int[] change) { | |
926 c.reachableBasicblock(bciDelta, change); | |
927 } | |
928 }, change); | |
929 | |
930 // We will also mark successors of jsr's as alive. | |
931 switch (bytecode) { | |
932 case Bytecodes._jsr: | |
933 case Bytecodes._jsr_w: | |
934 if (Assert.ASSERTS_ENABLED) { | |
935 Assert.that(!fell_through, "should not happen"); | |
936 } | |
937 reachableBasicblock(bci + Bytecodes.lengthFor(bytecode), change); | |
938 break; | |
939 } | |
940 if (fell_through) { | |
941 // Mark successor as alive | |
942 if (_basic_blocks[i+1].isDead()) { | |
943 _basic_blocks[i+1].markAsAlive(); | |
944 change[0] = 1; | |
945 } | |
946 } | |
947 } | |
948 } | |
949 } | |
950 } | |
951 | |
952 void reachableBasicblock (int bci, int[] data) { | |
953 if (Assert.ASSERTS_ENABLED) { | |
954 Assert.that(bci>= 0 && bci < method().getCodeSize(), "index out of bounds"); | |
955 } | |
956 BasicBlock bb = getBasicBlockAt(bci); | |
957 if (bb.isDead()) { | |
958 bb.markAsAlive(); | |
959 data[0] = 1; // Mark basicblock as changed | |
960 } | |
961 } | |
962 | |
963 // Interpretation methods (primary) | |
964 void doInterpretation () { | |
965 // "i" is just for debugging, so we can detect cases where this loop is | |
966 // iterated more than once. | |
967 int i = 0; | |
968 do { | |
969 // FIXME: remove | |
970 // if (TraceNewOopMapGeneration) { | |
971 // tty.print("\n\nIteration #%d of do_interpretation loop, method:\n", i); | |
972 // method().print_name(tty); | |
973 // tty.print("\n\n"); | |
974 // } | |
975 _conflict = false; | |
976 _monitor_safe = true; | |
977 // init_state is now called from init_basic_blocks. The length of a | |
978 // state vector cannot be determined until we have made a pass through | |
979 // the bytecodes counting the possible monitor entries. | |
980 if (!_got_error) initBasicBlocks(); | |
981 if (!_got_error) setupMethodEntryState(); | |
982 if (!_got_error) interpAll(); | |
983 if (!_got_error) rewriteRefvalConflicts(); | |
984 i++; | |
985 } while (_conflict && !_got_error); | |
986 } | |
987 | |
988 void initBasicBlocks () { | |
989 // Note: Could consider reserving only the needed space for each BB's state | |
990 // (entry stack may not be of maximal height for every basic block). | |
991 // But cumbersome since we don't know the stack heights yet. (Nor the | |
992 // monitor stack heights...) | |
993 | |
994 _basic_blocks = new BasicBlock[_bb_count]; | |
995 for (int i = 0; i < _bb_count; i++) { | |
996 _basic_blocks[i] = new BasicBlock(); | |
997 } | |
998 | |
999 // Make a pass through the bytecodes. Count the number of monitorenters. | |
1000 // This can be used an upper bound on the monitor stack depth in programs | |
1001 // which obey stack discipline with their monitor usage. Initialize the | |
1002 // known information about basic blocks. | |
1003 BytecodeStream j = new BytecodeStream(_method); | |
1004 int bytecode; | |
1005 | |
1006 int bbNo = 0; | |
1007 int monitor_count = 0; | |
1008 int prev_bci = -1; | |
1009 while( (bytecode = j.next()) >= 0) { | |
1010 if (j.code() == Bytecodes._monitorenter) { | |
1011 monitor_count++; | |
1012 } | |
1013 | |
1014 int bci = j.bci(); | |
1015 if (isBBHeader(bci)) { | |
1016 // Initialize the basicblock structure | |
1017 BasicBlock bb = _basic_blocks[bbNo]; | |
1018 bb._bci = bci; | |
1019 bb._max_locals = _max_locals; | |
1020 bb._max_stack = _max_stack; | |
1021 bb.setChanged(false); | |
1022 bb._stack_top = BasicBlock._dead_basic_block; // Initialize all basicblocks are dead. | |
1023 bb._monitor_top = bad_monitors; | |
1024 | |
1025 if (bbNo > 0) { | |
1026 _basic_blocks[bbNo - 1]._end_bci = prev_bci; | |
1027 } | |
1028 | |
1029 bbNo++; | |
1030 } | |
1031 // Remember prevous bci. | |
1032 prev_bci = bci; | |
1033 } | |
1034 // Set | |
1035 _basic_blocks[bbNo-1]._end_bci = prev_bci; | |
1036 | |
1037 _max_monitors = monitor_count; | |
1038 | |
1039 // Now that we have a bound on the depth of the monitor stack, we can | |
1040 // initialize the CellTypeState-related information. | |
1041 initState(); | |
1042 | |
1043 // We allocate space for all state-vectors for all basicblocks in one huge chuck. | |
1044 // Then in the next part of the code, we set a pointer in each _basic_block that | |
1045 // points to each piece. | |
1046 CellTypeStateList basicBlockState = new CellTypeStateList(bbNo * _state_len); | |
1047 | |
1048 // Make a pass over the basicblocks and assign their state vectors. | |
1049 for (int blockNum=0; blockNum < bbNo; blockNum++) { | |
1050 BasicBlock bb = _basic_blocks[blockNum]; | |
1051 bb._state = basicBlockState.subList(blockNum * _state_len, (blockNum + 1) * _state_len); | |
1052 | |
1053 if (Assert.ASSERTS_ENABLED) { | |
1054 if (blockNum + 1 < bbNo) { | |
1055 int bc_len = Bytecodes.javaLengthAt(_method, bb._end_bci); | |
1056 Assert.that(bb._end_bci + bc_len == _basic_blocks[blockNum + 1]._bci, | |
1057 "unmatched bci info in basicblock"); | |
1058 } | |
1059 } | |
1060 } | |
1061 if (Assert.ASSERTS_ENABLED) { | |
1062 BasicBlock bb = _basic_blocks[bbNo-1]; | |
1063 int bc_len = Bytecodes.javaLengthAt(_method, bb._end_bci); | |
1064 Assert.that(bb._end_bci + bc_len == _method.getCodeSize(), "wrong end bci"); | |
1065 } | |
1066 | |
1067 // Check that the correct number of basicblocks was found | |
1068 if (bbNo !=_bb_count) { | |
1069 if (bbNo < _bb_count) { | |
1070 throw new RuntimeException("jump into the middle of instruction?"); | |
1071 } else { | |
1072 throw new RuntimeException("extra basic blocks - should not happen?"); | |
1073 } | |
1074 } | |
1075 | |
1076 // Mark all alive blocks | |
1077 markReachableCode(); | |
1078 } | |
1079 | |
1080 void setupMethodEntryState () { | |
1081 // Initialize all locals to 'uninit' and set stack-height to 0 | |
1082 makeContextUninitialized(); | |
1083 | |
1084 // Initialize CellState type of arguments | |
1085 methodsigToEffect(method().getSignature(), method().isStatic(), vars()); | |
1086 | |
1087 // If some references must be pre-assigned to null, then set that up | |
1088 initializeVars(); | |
1089 | |
1090 // This is the start state | |
1091 mergeStateIntoBB(_basic_blocks[0]); | |
1092 | |
1093 if (Assert.ASSERTS_ENABLED) { | |
1094 Assert.that(_basic_blocks[0].changed(), "we are not getting off the ground"); | |
1095 } | |
1096 } | |
1097 | |
1098 void interpAll () { | |
1099 boolean change = true; | |
1100 | |
1101 while (change && !_got_error) { | |
1102 change = false; | |
1103 for (int i = 0; i < _bb_count && !_got_error; i++) { | |
1104 BasicBlock bb = _basic_blocks[i]; | |
1105 if (bb.changed()) { | |
1106 if (_got_error) return; | |
1107 change = true; | |
1108 bb.setChanged(false); | |
1109 interpBB(bb); | |
1110 } | |
1111 } | |
1112 } | |
1113 } | |
1114 | |
1115 // | |
1116 // Interpretation methods (secondary) | |
1117 // | |
1118 | |
1119 /** Sets the current state to be the state after executing the | |
1120 current instruction, starting in the current state. */ | |
1121 void interp1 (BytecodeStream itr) { | |
1122 if (DEBUG) { | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1123 System.err.println(" - bci " + itr.bci() + " " + itr.code()); |
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1124 printCurrentState(System.err, itr, false); |
0 | 1125 } |
1126 | |
1127 // if (TraceNewOopMapGeneration) { | |
1128 // print_current_state(tty, itr, TraceNewOopMapGenerationDetailed); | |
1129 // } | |
1130 | |
1131 // Should we report the results? Result is reported *before* the | |
1132 // instruction at the current bci is executed. However, not for | |
1133 // calls. For calls we do not want to include the arguments, so we | |
1134 // postpone the reporting until they have been popped (in method | |
1135 // ppl). | |
1136 if (_report_result == true) { | |
1137 switch(itr.code()) { | |
1138 case Bytecodes._invokevirtual: | |
1139 case Bytecodes._invokespecial: | |
1140 case Bytecodes._invokestatic: | |
1141 case Bytecodes._invokeinterface: | |
1602 | 1142 case Bytecodes._invokedynamic: |
0 | 1143 _itr_send = itr; |
1144 _report_result_for_send = true; | |
1145 break; | |
1146 default: | |
1147 fillStackmapForOpcodes(itr, vars(), stack(), _stack_top); | |
1148 break; | |
1149 } | |
1150 } | |
1151 | |
1152 // abstract interpretation of current opcode | |
1153 switch(itr.code()) { | |
1154 case Bytecodes._nop: break; | |
1155 case Bytecodes._goto: break; | |
1156 case Bytecodes._goto_w: break; | |
1157 case Bytecodes._iinc: break; | |
1158 case Bytecodes._return: doReturnMonitorCheck(); | |
1159 break; | |
1160 | |
1161 case Bytecodes._aconst_null: | |
1162 case Bytecodes._new: ppush1(CellTypeState.makeLineRef(itr.bci())); | |
1163 break; | |
1164 | |
1165 case Bytecodes._iconst_m1: | |
1166 case Bytecodes._iconst_0: | |
1167 case Bytecodes._iconst_1: | |
1168 case Bytecodes._iconst_2: | |
1169 case Bytecodes._iconst_3: | |
1170 case Bytecodes._iconst_4: | |
1171 case Bytecodes._iconst_5: | |
1172 case Bytecodes._fconst_0: | |
1173 case Bytecodes._fconst_1: | |
1174 case Bytecodes._fconst_2: | |
1175 case Bytecodes._bipush: | |
1176 case Bytecodes._sipush: ppush1(valCTS); break; | |
1177 | |
1178 case Bytecodes._lconst_0: | |
1179 case Bytecodes._lconst_1: | |
1180 case Bytecodes._dconst_0: | |
1181 case Bytecodes._dconst_1: ppush(vvCTS); break; | |
1182 | |
1183 case Bytecodes._ldc2_w: ppush(vvCTS); break; | |
1184 | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1185 case Bytecodes._ldc: doLdc(itr.bci()); break; |
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1186 case Bytecodes._ldc_w: doLdc(itr.bci()); break; |
0 | 1187 |
1188 case Bytecodes._iload: | |
1189 case Bytecodes._fload: ppload(vCTS, itr.getIndex()); break; | |
1190 | |
1191 case Bytecodes._lload: | |
1192 case Bytecodes._dload: ppload(vvCTS,itr.getIndex()); break; | |
1193 | |
1194 case Bytecodes._aload: ppload(rCTS, itr.getIndex()); break; | |
1195 | |
1196 case Bytecodes._iload_0: | |
1197 case Bytecodes._fload_0: ppload(vCTS, 0); break; | |
1198 case Bytecodes._iload_1: | |
1199 case Bytecodes._fload_1: ppload(vCTS, 1); break; | |
1200 case Bytecodes._iload_2: | |
1201 case Bytecodes._fload_2: ppload(vCTS, 2); break; | |
1202 case Bytecodes._iload_3: | |
1203 case Bytecodes._fload_3: ppload(vCTS, 3); break; | |
1204 | |
1205 case Bytecodes._lload_0: | |
1206 case Bytecodes._dload_0: ppload(vvCTS, 0); break; | |
1207 case Bytecodes._lload_1: | |
1208 case Bytecodes._dload_1: ppload(vvCTS, 1); break; | |
1209 case Bytecodes._lload_2: | |
1210 case Bytecodes._dload_2: ppload(vvCTS, 2); break; | |
1211 case Bytecodes._lload_3: | |
1212 case Bytecodes._dload_3: ppload(vvCTS, 3); break; | |
1213 | |
1214 case Bytecodes._aload_0: ppload(rCTS, 0); break; | |
1215 case Bytecodes._aload_1: ppload(rCTS, 1); break; | |
1216 case Bytecodes._aload_2: ppload(rCTS, 2); break; | |
1217 case Bytecodes._aload_3: ppload(rCTS, 3); break; | |
1218 | |
1219 case Bytecodes._iaload: | |
1220 case Bytecodes._faload: | |
1221 case Bytecodes._baload: | |
1222 case Bytecodes._caload: | |
1223 case Bytecodes._saload: pp(vrCTS, vCTS); break; | |
1224 | |
1225 case Bytecodes._laload: pp(vrCTS, vvCTS); break; | |
1226 case Bytecodes._daload: pp(vrCTS, vvCTS); break; | |
1227 | |
1228 case Bytecodes._aaload: ppNewRef(vrCTS, itr.bci()); break; | |
1229 | |
1230 case Bytecodes._istore: | |
1231 case Bytecodes._fstore: ppstore(vCTS, itr.getIndex()); break; | |
1232 | |
1233 case Bytecodes._lstore: | |
1234 case Bytecodes._dstore: ppstore(vvCTS, itr.getIndex()); break; | |
1235 | |
1236 case Bytecodes._astore: doAstore(itr.getIndex()); break; | |
1237 | |
1238 case Bytecodes._istore_0: | |
1239 case Bytecodes._fstore_0: ppstore(vCTS, 0); break; | |
1240 case Bytecodes._istore_1: | |
1241 case Bytecodes._fstore_1: ppstore(vCTS, 1); break; | |
1242 case Bytecodes._istore_2: | |
1243 case Bytecodes._fstore_2: ppstore(vCTS, 2); break; | |
1244 case Bytecodes._istore_3: | |
1245 case Bytecodes._fstore_3: ppstore(vCTS, 3); break; | |
1246 | |
1247 case Bytecodes._lstore_0: | |
1248 case Bytecodes._dstore_0: ppstore(vvCTS, 0); break; | |
1249 case Bytecodes._lstore_1: | |
1250 case Bytecodes._dstore_1: ppstore(vvCTS, 1); break; | |
1251 case Bytecodes._lstore_2: | |
1252 case Bytecodes._dstore_2: ppstore(vvCTS, 2); break; | |
1253 case Bytecodes._lstore_3: | |
1254 case Bytecodes._dstore_3: ppstore(vvCTS, 3); break; | |
1255 | |
1256 case Bytecodes._astore_0: doAstore(0); break; | |
1257 case Bytecodes._astore_1: doAstore(1); break; | |
1258 case Bytecodes._astore_2: doAstore(2); break; | |
1259 case Bytecodes._astore_3: doAstore(3); break; | |
1260 | |
1261 case Bytecodes._iastore: | |
1262 case Bytecodes._fastore: | |
1263 case Bytecodes._bastore: | |
1264 case Bytecodes._castore: | |
1265 case Bytecodes._sastore: ppop(vvrCTS); break; | |
1266 case Bytecodes._lastore: | |
1267 case Bytecodes._dastore: ppop(vvvrCTS); break; | |
1268 case Bytecodes._aastore: ppop(rvrCTS); break; | |
1269 | |
1270 case Bytecodes._pop: ppopAny(1); break; | |
1271 case Bytecodes._pop2: ppopAny(2); break; | |
1272 | |
1273 case Bytecodes._dup: ppdupswap(1, "11"); break; | |
1274 case Bytecodes._dup_x1: ppdupswap(2, "121"); break; | |
1275 case Bytecodes._dup_x2: ppdupswap(3, "1321"); break; | |
1276 case Bytecodes._dup2: ppdupswap(2, "2121"); break; | |
1277 case Bytecodes._dup2_x1: ppdupswap(3, "21321"); break; | |
1278 case Bytecodes._dup2_x2: ppdupswap(4, "214321"); break; | |
1279 case Bytecodes._swap: ppdupswap(2, "12"); break; | |
1280 | |
1281 case Bytecodes._iadd: | |
1282 case Bytecodes._fadd: | |
1283 case Bytecodes._isub: | |
1284 case Bytecodes._fsub: | |
1285 case Bytecodes._imul: | |
1286 case Bytecodes._fmul: | |
1287 case Bytecodes._idiv: | |
1288 case Bytecodes._fdiv: | |
1289 case Bytecodes._irem: | |
1290 case Bytecodes._frem: | |
1291 case Bytecodes._ishl: | |
1292 case Bytecodes._ishr: | |
1293 case Bytecodes._iushr: | |
1294 case Bytecodes._iand: | |
1295 case Bytecodes._ior: | |
1296 case Bytecodes._ixor: | |
1297 case Bytecodes._l2f: | |
1298 case Bytecodes._l2i: | |
1299 case Bytecodes._d2f: | |
1300 case Bytecodes._d2i: | |
1301 case Bytecodes._fcmpl: | |
1302 case Bytecodes._fcmpg: pp(vvCTS, vCTS); break; | |
1303 | |
1304 case Bytecodes._ladd: | |
1305 case Bytecodes._dadd: | |
1306 case Bytecodes._lsub: | |
1307 case Bytecodes._dsub: | |
1308 case Bytecodes._lmul: | |
1309 case Bytecodes._dmul: | |
1310 case Bytecodes._ldiv: | |
1311 case Bytecodes._ddiv: | |
1312 case Bytecodes._lrem: | |
1313 case Bytecodes._drem: | |
1314 case Bytecodes._land: | |
1315 case Bytecodes._lor: | |
1316 case Bytecodes._lxor: pp(vvvvCTS, vvCTS); break; | |
1317 | |
1318 case Bytecodes._ineg: | |
1319 case Bytecodes._fneg: | |
1320 case Bytecodes._i2f: | |
1321 case Bytecodes._f2i: | |
1322 case Bytecodes._i2c: | |
1323 case Bytecodes._i2s: | |
1324 case Bytecodes._i2b: pp(vCTS, vCTS); break; | |
1325 | |
1326 case Bytecodes._lneg: | |
1327 case Bytecodes._dneg: | |
1328 case Bytecodes._l2d: | |
1329 case Bytecodes._d2l: pp(vvCTS, vvCTS); break; | |
1330 | |
1331 case Bytecodes._lshl: | |
1332 case Bytecodes._lshr: | |
1333 case Bytecodes._lushr: pp(vvvCTS, vvCTS); break; | |
1334 | |
1335 case Bytecodes._i2l: | |
1336 case Bytecodes._i2d: | |
1337 case Bytecodes._f2l: | |
1338 case Bytecodes._f2d: pp(vCTS, vvCTS); break; | |
1339 | |
1340 case Bytecodes._lcmp: pp(vvvvCTS, vCTS); break; | |
1341 case Bytecodes._dcmpl: | |
1342 case Bytecodes._dcmpg: pp(vvvvCTS, vCTS); break; | |
1343 | |
1344 case Bytecodes._ifeq: | |
1345 case Bytecodes._ifne: | |
1346 case Bytecodes._iflt: | |
1347 case Bytecodes._ifge: | |
1348 case Bytecodes._ifgt: | |
1349 case Bytecodes._ifle: | |
1350 case Bytecodes._tableswitch: ppop1(valCTS); | |
1351 break; | |
1352 case Bytecodes._ireturn: | |
1353 case Bytecodes._freturn: doReturnMonitorCheck(); | |
1354 ppop1(valCTS); | |
1355 break; | |
1356 case Bytecodes._if_icmpeq: | |
1357 case Bytecodes._if_icmpne: | |
1358 case Bytecodes._if_icmplt: | |
1359 case Bytecodes._if_icmpge: | |
1360 case Bytecodes._if_icmpgt: | |
1361 case Bytecodes._if_icmple: ppop(vvCTS); | |
1362 break; | |
1363 | |
1364 case Bytecodes._lreturn: doReturnMonitorCheck(); | |
1365 ppop(vvCTS); | |
1366 break; | |
1367 | |
1368 case Bytecodes._dreturn: doReturnMonitorCheck(); | |
1369 ppop(vvCTS); | |
1370 break; | |
1371 | |
1372 case Bytecodes._if_acmpeq: | |
1373 case Bytecodes._if_acmpne: ppop(rrCTS); break; | |
1374 | |
1375 case Bytecodes._jsr: doJsr(itr.dest()); break; | |
1376 case Bytecodes._jsr_w: doJsr(itr.dest_w()); break; | |
1377 | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1378 case Bytecodes._getstatic: doField(true, true, itr.getIndexU2Cpcache(), itr.bci()); break; |
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1379 case Bytecodes._putstatic: doField(false, true, itr.getIndexU2Cpcache(), itr.bci()); break; |
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1380 case Bytecodes._getfield: doField(true, false, itr.getIndexU2Cpcache(), itr.bci()); break; |
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1381 case Bytecodes._putfield: doField(false, false, itr.getIndexU2Cpcache(), itr.bci()); break; |
0 | 1382 |
1383 case Bytecodes._invokevirtual: | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1384 case Bytecodes._invokespecial: doMethod(false, false, itr.getIndexU2Cpcache(), itr.bci()); break; |
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1385 case Bytecodes._invokestatic: doMethod(true, false, itr.getIndexU2Cpcache(), itr.bci()); break; |
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1386 case Bytecodes._invokedynamic: doMethod(true, false, itr.getIndexU4(), itr.bci()); break; |
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1387 case Bytecodes._invokeinterface: doMethod(false, true, itr.getIndexU2Cpcache(), itr.bci()); break; |
0 | 1388 case Bytecodes._newarray: |
1389 case Bytecodes._anewarray: ppNewRef(vCTS, itr.bci()); break; | |
1390 case Bytecodes._checkcast: doCheckcast(); break; | |
1391 case Bytecodes._arraylength: | |
1392 case Bytecodes._instanceof: pp(rCTS, vCTS); break; | |
1393 case Bytecodes._monitorenter: doMonitorenter(itr.bci()); break; | |
1394 case Bytecodes._monitorexit: doMonitorexit(itr.bci()); break; | |
1395 | |
1396 case Bytecodes._athrow: // handled by do_exception_edge() BUT ... | |
1397 // vlh(apple): doExceptionEdge() does not get | |
1398 // called if method has no exception handlers | |
1399 if ((!_has_exceptions) && (_monitor_top > 0)) { | |
1400 _monitor_safe = false; | |
1401 } | |
1402 break; | |
1403 | |
1404 case Bytecodes._areturn: doReturnMonitorCheck(); | |
1405 ppop1(refCTS); | |
1406 break; | |
1407 case Bytecodes._ifnull: | |
1408 case Bytecodes._ifnonnull: ppop1(refCTS); break; | |
1409 case Bytecodes._multianewarray: doMultianewarray(itr.codeAt(itr.bci() + 3), itr.bci()); break; | |
1410 | |
1411 case Bytecodes._wide: throw new RuntimeException("Iterator should skip this bytecode"); | |
1412 case Bytecodes._ret: break; | |
1413 | |
1414 // Java opcodes | |
1415 case Bytecodes._fast_aaccess_0: ppNewRef(rCTS, itr.bci()); break; // Pair bytecode for (aload_0, _fast_agetfield) | |
1416 | |
1417 case Bytecodes._fast_iaccess_0: ppush1(valCTS); break; // Pair bytecode for (aload_0, _fast_igetfield) | |
1418 | |
1419 case Bytecodes._fast_igetfield: pp(rCTS, vCTS); break; | |
1420 | |
1421 case Bytecodes._fast_agetfield: ppNewRef(rCTS, itr.bci()); break; | |
1422 | |
1423 case Bytecodes._fast_aload_0: ppload(rCTS, 0); break; | |
1424 | |
1425 case Bytecodes._lookupswitch: | |
1426 case Bytecodes._fast_linearswitch: | |
1427 case Bytecodes._fast_binaryswitch: ppop1(valCTS); break; | |
1428 | |
1429 default: | |
1430 throw new RuntimeException("unexpected opcode: " + itr.code()); | |
1431 } | |
1432 } | |
1433 | |
1434 void doExceptionEdge (BytecodeStream itr) { | |
1435 // Only check exception edge, if bytecode can trap | |
1436 if (!Bytecodes.canTrap(itr.code())) return; | |
1437 switch (itr.code()) { | |
1438 case Bytecodes._aload_0: | |
1439 case Bytecodes._fast_aload_0: | |
1440 // These bytecodes can trap for rewriting. We need to assume that | |
1441 // they do not throw exceptions to make the monitor analysis work. | |
1442 return; | |
1443 | |
1444 case Bytecodes._ireturn: | |
1445 case Bytecodes._lreturn: | |
1446 case Bytecodes._freturn: | |
1447 case Bytecodes._dreturn: | |
1448 case Bytecodes._areturn: | |
1449 case Bytecodes._return: | |
1450 // If the monitor stack height is not zero when we leave the method, | |
1451 // then we are either exiting with a non-empty stack or we have | |
1452 // found monitor trouble earlier in our analysis. In either case, | |
1453 // assume an exception could be taken here. | |
1454 if (_monitor_top == 0) { | |
1455 return; | |
1456 } | |
1457 break; | |
1458 | |
1459 case Bytecodes._monitorexit: | |
1460 // If the monitor stack height is bad_monitors, then we have detected a | |
1461 // monitor matching problem earlier in the analysis. If the | |
1462 // monitor stack height is 0, we are about to pop a monitor | |
1463 // off of an empty stack. In either case, the bytecode | |
1464 // could throw an exception. | |
1465 if (_monitor_top != bad_monitors && _monitor_top != 0) { | |
1466 return; | |
1467 } | |
1468 break; | |
1469 } | |
1470 | |
1471 if (_has_exceptions) { | |
1472 int bci = itr.bci(); | |
6213
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
1473 ExceptionTableElement[] exct = method().getExceptionTable(); |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
1474 for(int i = 0; i< exct.length; i++) { |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
1475 int start_pc = exct[i].getStartPC(); |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
1476 int end_pc = exct[i].getEndPC(); |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
1477 int handler_pc = exct[i].getHandlerPC(); |
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
1478 int catch_type = exct[i].getCatchTypeIndex(); |
0 | 1479 |
1480 if (start_pc <= bci && bci < end_pc) { | |
1481 BasicBlock excBB = getBasicBlockAt(handler_pc); | |
1482 CellTypeStateList excStk = excBB.stack(); | |
1483 CellTypeStateList cOpStck = stack(); | |
1484 CellTypeState cOpStck_0 = cOpStck.get(0).copy(); | |
1485 int cOpStackTop = _stack_top; | |
1486 | |
1487 // Exception stacks are always the same. | |
1488 if (Assert.ASSERTS_ENABLED) { | |
1489 Assert.that(method().getMaxStack() > 0, "sanity check"); | |
1490 } | |
1491 | |
1492 // We remembered the size and first element of "cOpStck" | |
1493 // above; now we temporarily set them to the appropriate | |
1494 // values for an exception handler. | |
1495 cOpStck.get(0).set(CellTypeState.makeSlotRef(_max_locals)); | |
1496 _stack_top = 1; | |
1497 | |
1498 mergeStateIntoBB(excBB); | |
1499 | |
1500 // Now undo the temporary change. | |
1501 cOpStck.get(0).set(cOpStck_0); | |
1502 _stack_top = cOpStackTop; | |
1503 | |
1504 // If this is a "catch all" handler, then we do not need to | |
1505 // consider any additional handlers. | |
1506 if (catch_type == 0) { | |
1507 return; | |
1508 } | |
1509 } | |
1510 } | |
1511 } | |
1512 | |
1513 // It is possible that none of the exception handlers would have caught | |
1514 // the exception. In this case, we will exit the method. We must | |
1515 // ensure that the monitor stack is empty in this case. | |
1516 if (_monitor_top == 0) { | |
1517 return; | |
1518 } | |
1519 | |
1520 // We pessimistically assume that this exception can escape the | |
1521 // method. (It is possible that it will always be caught, but | |
1522 // we don't care to analyse the types of the catch clauses.) | |
1523 | |
1524 // We don't set _monitor_top to bad_monitors because there are no successors | |
1525 // to this exceptional exit. | |
1526 | |
1527 if (TraceMonitorMismatch && _monitor_safe) { | |
1528 // We check _monitor_safe so that we only report the first mismatched | |
1529 // exceptional exit. | |
1530 reportMonitorMismatch("non-empty monitor stack at exceptional exit"); | |
1531 } | |
1532 _monitor_safe = false; | |
1533 } | |
1534 | |
1535 void checkType (CellTypeState expected, CellTypeState actual) { | |
1536 if (!expected.equalKind(actual)) { | |
1537 throw new RuntimeException("wrong type on stack (found: " + | |
1538 actual.toChar() + " expected: " + | |
1539 expected.toChar() + ")"); | |
1540 } | |
1541 } | |
1542 | |
1543 void ppstore (CellTypeState[] in, int loc_no) { | |
1544 for (int i = 0; i < in.length && !in[i].equal(CellTypeState.bottom); i++) { | |
1545 CellTypeState expected = in[i]; | |
1546 CellTypeState actual = pop(); | |
1547 checkType(expected, actual); | |
1548 if (Assert.ASSERTS_ENABLED) { | |
1549 Assert.that(loc_no >= 0, "sanity check"); | |
1550 } | |
1551 setVar(loc_no++, actual); | |
1552 } | |
1553 } | |
1554 | |
1555 void ppload (CellTypeState[] out, int loc_no) { | |
1556 for (int i = 0; i < out.length && !out[i].equal(CellTypeState.bottom); i++) { | |
1557 CellTypeState out1 = out[i]; | |
1558 CellTypeState vcts = getVar(loc_no); | |
1559 if (Assert.ASSERTS_ENABLED) { | |
1560 Assert.that(out1.canBeReference() || out1.canBeValue(), | |
1561 "can only load refs. and values."); | |
1562 } | |
1563 if (out1.isReference()) { | |
1564 if (Assert.ASSERTS_ENABLED) { | |
1565 Assert.that(loc_no>=0, "sanity check"); | |
1566 } | |
1567 if (!vcts.isReference()) { | |
1568 // We were asked to push a reference, but the type of the | |
1569 // variable can be something else | |
1570 _conflict = true; | |
1571 if (vcts.canBeUninit()) { | |
1572 // It is a ref-uninit conflict (at least). If there are other | |
1573 // problems, we'll get them in the next round | |
1574 addToRefInitSet(loc_no); | |
1575 vcts = out1; | |
1576 } else { | |
1577 // It wasn't a ref-uninit conflict. So must be a | |
1578 // ref-val or ref-pc conflict. Split the variable. | |
1579 recordRefvalConflict(loc_no); | |
1580 vcts = out1; | |
1581 } | |
1582 push(out1); // recover... | |
1583 } else { | |
1584 push(vcts); // preserve reference. | |
1585 } | |
1586 // Otherwise it is a conflict, but one that verification would | |
1587 // have caught if illegal. In particular, it can't be a topCTS | |
1588 // resulting from mergeing two difference pcCTS's since the verifier | |
1589 // would have rejected any use of such a merge. | |
1590 } else { | |
1591 push(out1); // handle val/init conflict | |
1592 } | |
1593 loc_no++; | |
1594 } | |
1595 } | |
1596 | |
1597 void ppush1 (CellTypeState in) { | |
1598 if (Assert.ASSERTS_ENABLED) { | |
1599 Assert.that(in.isReference() | in.isValue(), "sanity check"); | |
1600 } | |
1601 if (DEBUG) { | |
1602 System.err.println(" - pushing " + in.toChar()); | |
1603 } | |
1604 push(in); | |
1605 } | |
1606 | |
1607 void ppush (CellTypeState[] in) { | |
1608 for (int i = 0; i < in.length && !in[i].equal(CellTypeState.bottom); i++) { | |
1609 ppush1(in[i]); | |
1610 } | |
1611 } | |
1612 | |
1613 void ppush (CellTypeStateList in) { | |
1614 for (int i = 0; i < in.size() && !in.get(i).equal(CellTypeState.bottom); i++) { | |
1615 ppush1(in.get(i)); | |
1616 } | |
1617 } | |
1618 | |
1619 void ppop1 (CellTypeState out) { | |
1620 CellTypeState actual = pop(); | |
1621 if (DEBUG) { | |
1622 System.err.println(" - popping " + actual.toChar() + ", expecting " + out.toChar()); | |
1623 } | |
1624 checkType(out, actual); | |
1625 } | |
1626 | |
1627 void ppop (CellTypeState[] out) { | |
1628 for (int i = 0; i < out.length && !out[i].equal(CellTypeState.bottom); i++) { | |
1629 ppop1(out[i]); | |
1630 } | |
1631 } | |
1632 | |
1633 void ppopAny (int poplen) { | |
1634 if (_stack_top >= poplen) { | |
1635 _stack_top -= poplen; | |
1636 } else { | |
1637 throw new RuntimeException("stack underflow"); | |
1638 } | |
1639 } | |
1640 | |
1641 void pp (CellTypeState[] in, CellTypeState[] out) { | |
1642 ppop(in); | |
1643 ppush(out); | |
1644 } | |
1645 | |
1646 void ppNewRef (CellTypeState[] in, int bci) { | |
1647 ppop(in); | |
1648 ppush1(CellTypeState.makeLineRef(bci)); | |
1649 } | |
1650 | |
1651 void ppdupswap (int poplen, String out) { | |
1652 CellTypeState[] actual = new CellTypeState[5]; | |
1653 Assert.that(poplen < 5, "this must be less than length of actual vector"); | |
1654 | |
1655 // pop all arguments | |
1656 for(int i = 0; i < poplen; i++) actual[i] = pop(); | |
1657 | |
1658 // put them back | |
1659 for (int i = 0; i < out.length(); i++) { | |
1660 char push_ch = out.charAt(i); | |
1661 int idx = push_ch - '1'; | |
1662 if (Assert.ASSERTS_ENABLED) { | |
1663 Assert.that(idx >= 0 && idx < poplen, "wrong arguments"); | |
1664 } | |
1665 push(actual[idx]); | |
1666 } | |
1667 } | |
1668 | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1669 void doLdc (int bci) { |
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1670 BytecodeLoadConstant ldc = BytecodeLoadConstant.at(_method, bci); |
0 | 1671 ConstantPool cp = method().getConstants(); |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1672 BasicType bt = ldc.resultType(); |
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1673 CellTypeState cts = (bt == BasicType.T_OBJECT) ? CellTypeState.makeLineRef(bci) : valCTS; |
0 | 1674 ppush1(cts); |
1675 } | |
1676 | |
1677 void doAstore (int idx) { | |
1678 CellTypeState r_or_p = pop(); | |
1679 if (!r_or_p.isAddress() && !r_or_p.isReference()) { | |
1680 // We actually expected ref or pc, but we only report that we expected a ref. It does not | |
1681 // really matter (at least for now) | |
1682 throw new RuntimeException("wrong type on stack (found: " + | |
1683 r_or_p.toChar() + ", expected: {pr})"); | |
1684 } | |
1685 setVar(idx, r_or_p); | |
1686 } | |
1687 | |
1688 void doJsr (int targBCI) { | |
1689 push(CellTypeState.makeAddr(targBCI)); | |
1690 } | |
1691 | |
1692 void doField (boolean is_get, boolean is_static, int idx, int bci) { | |
1693 // Dig up signature for field in constant pool | |
1694 ConstantPool cp = method().getConstants(); | |
1695 int nameAndTypeIdx = cp.getNameAndTypeRefIndexAt(idx); | |
1696 int signatureIdx = cp.getSignatureRefIndexAt(nameAndTypeIdx); | |
1697 Symbol signature = cp.getSymbolAt(signatureIdx); | |
1698 | |
1699 if (DEBUG) { | |
1700 System.err.println("doField: signature = " + signature.asString() + ", idx = " + idx + | |
1701 ", nameAndTypeIdx = " + nameAndTypeIdx + ", signatureIdx = " + signatureIdx + ", bci = " + bci); | |
1702 } | |
1703 | |
1704 // Parse signature (espcially simple for fields) | |
1705 // The signature is UFT8 encoded, but the first char is always ASCII for signatures. | |
1706 char sigch = (char) signature.getByteAt(0); | |
1707 CellTypeState[] temp = new CellTypeState[4]; | |
1708 CellTypeState[] eff = sigcharToEffect(sigch, bci, temp); | |
1709 | |
1710 CellTypeState[] in = new CellTypeState[4]; | |
1711 CellTypeState[] out; | |
1712 int i = 0; | |
1713 | |
1714 if (is_get) { | |
1715 out = eff; | |
1716 } else { | |
1717 out = epsilonCTS; | |
1718 i = copyCTS(in, eff); | |
1719 } | |
1720 if (!is_static) in[i++] = CellTypeState.ref; | |
1721 in[i] = CellTypeState.bottom; | |
1722 if (Assert.ASSERTS_ENABLED) { | |
1723 Assert.that(i<=3, "sanity check"); | |
1724 } | |
1725 pp(in, out); | |
1726 } | |
1727 | |
1728 void doMethod (boolean is_static, boolean is_interface, int idx, int bci) { | |
1729 // Dig up signature for field in constant pool | |
1730 ConstantPool cp = _method.getConstants(); | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1731 Symbol signature = cp.getSignatureRefAt(idx); |
0 | 1732 |
1733 // Parse method signature | |
1734 CellTypeStateList out = new CellTypeStateList(4); | |
1735 CellTypeStateList in = new CellTypeStateList(MAXARGSIZE+1); // Includes result | |
1736 ComputeCallStack cse = new ComputeCallStack(signature); | |
1737 | |
1738 // Compute return type | |
1739 int res_length = cse.computeForReturntype(out); | |
1740 | |
1741 // Temporary hack. | |
1742 if (out.get(0).equal(CellTypeState.ref) && out.get(1).equal(CellTypeState.bottom)) { | |
1743 out.get(0).set(CellTypeState.makeLineRef(bci)); | |
1744 } | |
1745 | |
1746 if (Assert.ASSERTS_ENABLED) { | |
1747 Assert.that(res_length<=4, "max value should be vv"); | |
1748 } | |
1749 | |
1750 // Compute arguments | |
1751 int arg_length = cse.computeForParameters(is_static, in); | |
1752 if (Assert.ASSERTS_ENABLED) { | |
1753 Assert.that(arg_length<=MAXARGSIZE, "too many locals"); | |
1754 } | |
1755 | |
1756 // Pop arguments | |
1757 for (int i = arg_length - 1; i >= 0; i--) ppop1(in.get(i));// Do args in reverse order. | |
1758 | |
1759 // Report results | |
1760 if (_report_result_for_send == true) { | |
1761 fillStackmapForOpcodes(_itr_send, vars(), stack(), _stack_top); | |
1762 _report_result_for_send = false; | |
1763 } | |
1764 | |
1765 // Push return address | |
1766 ppush(out); | |
1767 } | |
1768 | |
1769 void doMultianewarray (int dims, int bci) { | |
1770 if (Assert.ASSERTS_ENABLED) { | |
1771 Assert.that(dims >= 1, "sanity check"); | |
1772 } | |
1773 for(int i = dims -1; i >=0; i--) { | |
1774 ppop1(valCTS); | |
1775 } | |
1776 ppush1(CellTypeState.makeLineRef(bci)); | |
1777 } | |
1778 | |
1779 void doMonitorenter (int bci) { | |
1780 CellTypeState actual = pop(); | |
1781 if (_monitor_top == bad_monitors) { | |
1782 return; | |
1783 } | |
1784 | |
1785 // Bail out when we get repeated locks on an identical monitor. This case | |
1786 // isn't too hard to handle and can be made to work if supporting nested | |
1787 // redundant synchronized statements becomes a priority. | |
1788 // | |
1789 // See also "Note" in do_monitorexit(), below. | |
1790 if (actual.isLockReference()) { | |
1791 _monitor_top = bad_monitors; | |
1792 _monitor_safe = false; | |
1793 | |
1794 if (TraceMonitorMismatch) { | |
1795 reportMonitorMismatch("nested redundant lock -- bailout..."); | |
1796 } | |
1797 return; | |
1798 } | |
1799 | |
1800 CellTypeState lock = CellTypeState.makeLockRef(bci); | |
1801 checkType(refCTS, actual); | |
1802 if (!actual.isInfoTop()) { | |
1803 replaceAllCTSMatches(actual, lock); | |
1804 monitorPush(lock); | |
1805 } | |
1806 } | |
1807 | |
1808 void doMonitorexit (int bci) { | |
1809 CellTypeState actual = pop(); | |
1810 if (_monitor_top == bad_monitors) { | |
1811 return; | |
1812 } | |
1813 checkType(refCTS, actual); | |
1814 CellTypeState expected = monitorPop(); | |
1815 if (!actual.isLockReference() || !expected.equal(actual)) { | |
1816 // The monitor we are exiting is not verifiably the one | |
1817 // on the top of our monitor stack. This causes a monitor | |
1818 // mismatch. | |
1819 _monitor_top = bad_monitors; | |
1820 _monitor_safe = false; | |
1821 | |
1822 // We need to mark this basic block as changed so that | |
1823 // this monitorexit will be visited again. We need to | |
1824 // do this to ensure that we have accounted for the | |
1825 // possibility that this bytecode will throw an | |
1826 // exception. | |
1827 BasicBlock bb = getBasicBlockContaining(bci); | |
1828 bb.setChanged(true); | |
1829 bb._monitor_top = bad_monitors; | |
1830 | |
1831 if (TraceMonitorMismatch) { | |
1832 reportMonitorMismatch("improper monitor pair"); | |
1833 } | |
1834 } else { | |
1835 // This code is a fix for the case where we have repeated | |
1836 // locking of the same object in straightline code. We clear | |
1837 // out the lock when it is popped from the monitor stack | |
1838 // and replace it with an unobtrusive reference value that can | |
1839 // be locked again. | |
1840 // | |
1841 // Note: when generateOopMap is fixed to properly handle repeated, | |
1842 // nested, redundant locks on the same object, then this | |
1843 // fix will need to be removed at that time. | |
1844 replaceAllCTSMatches(actual, CellTypeState.makeLineRef(bci)); | |
1845 } | |
1846 | |
1847 if (_report_for_exit_bci == bci) { | |
1848 _matching_enter_bci = expected.getMonitorSource(); | |
1849 } | |
1850 } | |
1851 | |
1852 void doReturnMonitorCheck () { | |
1853 if (_monitor_top > 0) { | |
1854 // The monitor stack must be empty when we leave the method | |
1855 // for the monitors to be properly matched. | |
1856 _monitor_safe = false; | |
1857 | |
1858 // Since there are no successors to the *return bytecode, it | |
1859 // isn't necessary to set _monitor_top to bad_monitors. | |
1860 | |
1861 if (TraceMonitorMismatch) { | |
1862 reportMonitorMismatch("non-empty monitor stack at return"); | |
1863 } | |
1864 } | |
1865 } | |
1866 | |
1867 void doCheckcast () { | |
1868 CellTypeState actual = pop(); | |
1869 checkType(refCTS, actual); | |
1870 push(actual); | |
1871 } | |
1872 | |
1873 CellTypeState[] sigcharToEffect (char sigch, int bci, CellTypeState[] out) { | |
1874 // Object and array | |
1875 if (sigch=='L' || sigch=='[') { | |
1876 out[0] = CellTypeState.makeLineRef(bci); | |
1877 out[1] = CellTypeState.bottom; | |
1878 return out; | |
1879 } | |
1880 if (sigch == 'J' || sigch == 'D' ) return vvCTS; // Long and Double | |
1881 if (sigch == 'V' ) return epsilonCTS; // Void | |
1882 return vCTS; // Otherwise | |
1883 } | |
1884 | |
1885 // Copies (optionally bottom/zero terminated) CTS string from "src" into "dst". | |
1886 // Does NOT terminate with a bottom. Returns the number of cells copied. | |
1887 int copyCTS (CellTypeState[] dst, CellTypeState[] src) { | |
1888 int idx = 0; | |
1889 for (; idx < src.length && !src[idx].isBottom(); idx++) { | |
1890 dst[idx] = src[idx]; | |
1891 } | |
1892 return idx; | |
1893 } | |
1894 | |
1895 // Create result set | |
1896 boolean _report_result; | |
1897 boolean _report_result_for_send; // Unfortunatly, stackmaps for sends are special, so we need some extra | |
1898 BytecodeStream _itr_send; // variables to handle them properly. | |
1899 | |
1900 void reportResult () { | |
1901 // if (TraceNewOopMapGeneration) tty.print_cr("Report result pass"); | |
1902 | |
1903 // We now want to report the result of the parse | |
1904 _report_result = true; | |
1905 | |
1906 // Prolog code | |
1907 fillStackmapProlog(_gc_points); | |
1908 | |
1909 // Mark everything changed, then do one interpretation pass. | |
1910 for (int i = 0; i<_bb_count; i++) { | |
1911 if (_basic_blocks[i].isReachable()) { | |
1912 _basic_blocks[i].setChanged(true); | |
1913 interpBB(_basic_blocks[i]); | |
1914 } | |
1915 } | |
1916 | |
1917 // Note: Since we are skipping dead-code when we are reporting results, then | |
1918 // the no. of encountered gc-points might be fewer than the previously number | |
1919 // we have counted. (dead-code is a pain - it should be removed before we get here) | |
1920 fillStackmapEpilog(); | |
1921 | |
1922 // Report initvars | |
1923 fillInitVars(_init_vars); | |
1924 | |
1925 _report_result = false; | |
1926 } | |
1927 | |
1928 // Initvars | |
1929 List/*<Integer>*/ _init_vars; | |
1930 | |
1931 void initializeVars () { | |
1932 for (int k = 0; k < _init_vars.size(); k++) | |
1933 _state.get(((Integer) _init_vars.get(k)).intValue()).set(CellTypeState.makeSlotRef(k)); | |
1934 } | |
1935 | |
1936 void addToRefInitSet (int localNo) { | |
1937 // if (TraceNewOopMapGeneration) | |
1938 // tty.print_cr("Added init vars: %d", localNo); | |
1939 | |
1940 Integer local = new Integer(localNo); | |
1941 | |
1942 // Is it already in the set? | |
1943 if (_init_vars.contains(local)) | |
1944 return; | |
1945 | |
1946 _init_vars.add(local); | |
1947 } | |
1948 | |
1949 // Conflicts rewrite logic | |
1950 boolean _conflict; // True, if a conflict occured during interpretation | |
1951 int _nof_refval_conflicts; // No. of conflicts that require rewrites | |
1952 int[] _new_var_map; | |
1953 | |
1954 void recordRefvalConflict (int varNo) { | |
1955 if (Assert.ASSERTS_ENABLED) { | |
1956 Assert.that(varNo>=0 && varNo< _max_locals, "index out of range"); | |
1957 } | |
1958 | |
1959 if (TraceOopMapRewrites) { | |
1960 System.err.println("### Conflict detected (local no: " + varNo + ")"); | |
1961 } | |
1962 | |
1963 if (_new_var_map == null) { | |
1964 _new_var_map = new int[_max_locals]; | |
1965 for (int k = 0; k < _max_locals; k++) _new_var_map[k] = k; | |
1966 } | |
1967 | |
1968 if ( _new_var_map[varNo] == varNo) { | |
1969 // Check if max. number of locals has been reached | |
1970 if (_max_locals + _nof_refval_conflicts >= MAX_LOCAL_VARS) { | |
1971 throw new RuntimeException("Rewriting exceeded local variable limit"); | |
1972 } | |
1973 _new_var_map[varNo] = _max_locals + _nof_refval_conflicts; | |
1974 _nof_refval_conflicts++; | |
1975 } | |
1976 } | |
1977 | |
1978 void rewriteRefvalConflicts () { | |
1979 if (_nof_refval_conflicts > 0) { | |
1980 if (VM.getVM().isDebugging()) { | |
1981 throw new RuntimeException("Should not reach here (method rewriting should have been done by the VM already)"); | |
1982 } else { | |
1983 throw new RuntimeException("Method rewriting not yet implemented in Java"); | |
1984 } | |
1985 } | |
1986 } | |
1987 // Rewriting-related routines are not needed here | |
1988 // void rewrite_refval_conflict (int from, int to); | |
1989 // bool rewrite_refval_conflict_inst (BytecodeStream *i, int from, int to); | |
1990 // bool rewrite_load_or_store (BytecodeStream *i, Bytecodes.Code bc, Bytecodes.Code bc0, unsigned int varNo); | |
1991 | |
1992 // bool expand_current_instr (int bci, int ilen, int newIlen, u_char inst_buffer[]); | |
1993 // bool is_astore (BytecodeStream *itr, int *index); | |
1994 // bool is_aload (BytecodeStream *itr, int *index); | |
1995 | |
1996 // List of bci's where a return address is on top of the stack | |
1997 // GrowableArray<intptr_t> *_ret_adr_tos; | |
1998 | |
1999 // bool stack_top_holds_ret_addr (int bci); | |
2000 // void compute_ret_adr_at_TOS (); | |
2001 // void update_ret_adr_at_TOS (int bci, int delta); | |
2002 | |
2003 String stateVecToString (CellTypeStateList vec, int len) { | |
2004 for (int i = 0; i < len; i++) { | |
2005 _state_vec_buf[i] = vec.get(i).toChar(); | |
2006 } | |
2007 return new String(_state_vec_buf, 0, len); | |
2008 } | |
2009 | |
2010 // Helper method. Can be used in subclasses to fx. calculate gc_points. If the current instuction | |
2011 // is a control transfer, then calls the jmpFct all possible destinations. | |
2012 void retJumpTargetsDo (BytecodeStream bcs, JumpClosure closure, int varNo, int[] data) { | |
2013 CellTypeState ra = vars().get(varNo); | |
2014 if (!ra.isGoodAddress()) { | |
2015 throw new RuntimeException("ret returns from two jsr subroutines?"); | |
2016 } | |
2017 int target = ra.getInfo(); | |
2018 | |
2019 RetTableEntry rtEnt = _rt.findJsrsForTarget(target); | |
2020 int bci = bcs.bci(); | |
2021 for (int i = 0; i < rtEnt.nofJsrs(); i++) { | |
2022 int target_bci = rtEnt.jsrs(i); | |
2023 // Make sure a jrtRet does not set the changed bit for dead basicblock. | |
2024 BasicBlock jsr_bb = getBasicBlockContaining(target_bci - 1); | |
2025 if (Assert.ASSERTS_ENABLED) { | |
2026 BasicBlock target_bb = _basic_blocks[1 + bbIndex(jsr_bb)]; | |
2027 Assert.that(target_bb == getBasicBlockAt(target_bci), "wrong calc. of successor basicblock"); | |
2028 } | |
2029 boolean alive = jsr_bb.isAlive(); | |
2030 // if (TraceNewOopMapGeneration) { | |
2031 // tty.print("pc = %d, ret . %d alive: %s\n", bci, target_bci, alive ? "true" : "false"); | |
2032 // } | |
2033 if (alive) { | |
2034 closure.process(this, target_bci, data); | |
2035 } | |
2036 } | |
2037 } | |
2038 | |
2039 /** If the current instruction in "c" has no effect on control flow, | |
2040 returns "true". Otherwise, calls "closure.process()" one or | |
2041 more times, with "c", an appropriate "pcDelta", and "data" as | |
2042 arguments, then returns "false". There is one exception: if the | |
2043 current instruction is a "ret", returns "false" without calling | |
2044 "jmpFct". Arrangements for tracking the control flow of a "ret" | |
2045 must be made externally. */ | |
2046 boolean jumpTargetsDo (BytecodeStream bcs, JumpClosure closure, int[] data) { | |
2047 int bci = bcs.bci(); | |
2048 | |
2049 switch (bcs.code()) { | |
2050 case Bytecodes._ifeq: | |
2051 case Bytecodes._ifne: | |
2052 case Bytecodes._iflt: | |
2053 case Bytecodes._ifge: | |
2054 case Bytecodes._ifgt: | |
2055 case Bytecodes._ifle: | |
2056 case Bytecodes._if_icmpeq: | |
2057 case Bytecodes._if_icmpne: | |
2058 case Bytecodes._if_icmplt: | |
2059 case Bytecodes._if_icmpge: | |
2060 case Bytecodes._if_icmpgt: | |
2061 case Bytecodes._if_icmple: | |
2062 case Bytecodes._if_acmpeq: | |
2063 case Bytecodes._if_acmpne: | |
2064 case Bytecodes._ifnull: | |
2065 case Bytecodes._ifnonnull: | |
2066 closure.process(this, bcs.dest(), data); | |
2067 closure.process(this, bci + 3, data); | |
2068 break; | |
2069 | |
2070 case Bytecodes._goto: | |
2071 closure.process(this, bcs.dest(), data); | |
2072 break; | |
2073 case Bytecodes._goto_w: | |
2074 closure.process(this, bcs.dest_w(), data); | |
2075 break; | |
2076 case Bytecodes._tableswitch: | |
2077 { | |
2078 BytecodeTableswitch tableswitch = BytecodeTableswitch.at(bcs); | |
2079 int len = tableswitch.length(); | |
2080 | |
2081 closure.process(this, bci + tableswitch.defaultOffset(), data); /* Default. jump address */ | |
2082 while (--len >= 0) { | |
2083 closure.process(this, bci + tableswitch.destOffsetAt(len), data); | |
2084 } | |
2085 break; | |
2086 } | |
2087 | |
2088 case Bytecodes._fast_linearswitch: // Java opcodes | |
2089 case Bytecodes._fast_binaryswitch: // get_int_table handles conversions | |
2090 case Bytecodes._lookupswitch: | |
2091 { | |
2092 BytecodeLookupswitch lookupswitch = BytecodeLookupswitch.at(bcs); | |
2093 int npairs = lookupswitch.numberOfPairs(); | |
2094 closure.process(this, bci + lookupswitch.defaultOffset(), data); /* Default. */ | |
2095 while(--npairs >= 0) { | |
2096 LookupswitchPair pair = lookupswitch.pairAt(npairs); | |
2097 closure.process(this, bci + pair.offset(), data); | |
2098 } | |
2099 break; | |
2100 } | |
2101 case Bytecodes._jsr: | |
2102 Assert.that(bcs.isWide()==false, "sanity check"); | |
2103 closure.process(this, bcs.dest(), data); | |
2104 break; | |
2105 case Bytecodes._jsr_w: | |
2106 closure.process(this, bcs.dest_w(), data); | |
2107 break; | |
2108 case Bytecodes._wide: | |
2109 throw new RuntimeException("Should not reach here"); | |
2110 case Bytecodes._athrow: | |
2111 case Bytecodes._ireturn: | |
2112 case Bytecodes._lreturn: | |
2113 case Bytecodes._freturn: | |
2114 case Bytecodes._dreturn: | |
2115 case Bytecodes._areturn: | |
2116 case Bytecodes._return: | |
2117 case Bytecodes._ret: | |
2118 break; | |
2119 default: | |
2120 return true; | |
2121 } | |
2122 return false; | |
2123 } | |
2124 | |
2125 // Monitor matching | |
2126 // int fill_out_arrays (int *enter, int *exit, int max); | |
2127 | |
2128 // friend class RelocCallback; | |
2129 | |
2130 //---------------------------------------------------------------------- | |
2131 // Public routines for GenerateOopMap | |
2132 // | |
2133 public GenerateOopMap(Method method) { | |
2134 // We have to initialize all variables here, that can be queried direcly | |
2135 _method = method; | |
2136 _max_locals=0; | |
2137 _init_vars = null; | |
2138 _rt = new RetTable(); | |
2139 } | |
2140 | |
2141 | |
2142 // Compute the map. | |
2143 public void computeMap() { | |
2144 if (DEBUG) { | |
2145 System.err.println("*** GenerateOopMap: computing for " + | |
2146 method().getMethodHolder().getName().asString() + "." + | |
2147 method().getName().asString() + | |
2148 method().getSignature().asString()); | |
2149 } | |
2150 | |
2151 // Initialize values | |
2152 _got_error = false; | |
2153 _conflict = false; | |
2154 _max_locals = (int) method().getMaxLocals(); | |
2155 _max_stack = (int) method().getMaxStack(); | |
6213
8150fa46d2ed
7178145: Change constMethodOop::_exception_table to optionally inlined u2 table.
jiangli
parents:
3838
diff
changeset
|
2156 _has_exceptions = (method().hasExceptionTable()); |
0 | 2157 _nof_refval_conflicts = 0; |
2158 _init_vars = new ArrayList(5); // There are seldom more than 5 init_vars | |
2159 _report_result = false; | |
2160 _report_result_for_send = false; | |
2161 _report_for_exit_bci = -1; | |
2162 _new_var_map = null; | |
2163 // _ret_adr_tos = new GrowableArray<intptr_t>(5); // 5 seems like a good number; | |
2164 // _did_rewriting = false; | |
2165 // _did_relocation = false; | |
2166 | |
2167 // FIXME: remove | |
2168 /* | |
2169 if (TraceNewOopMapGeneration) { | |
2170 tty.print("Method name: %s\n", method().name().as_C_string()); | |
2171 if (Verbose) { | |
2172 _method.print_codes(); | |
2173 tty.print_cr("Exception table:"); | |
2174 typeArrayOop excps = method().exception_table(); | |
2175 for(int i = 0; i < excps.length(); i += 4) { | |
2176 tty.print_cr("[%d - %d] . %d", excps.int_at(i + 0), excps.int_at(i + 1), excps.int_at(i + 2)); | |
2177 } | |
2178 } | |
2179 } | |
2180 */ | |
2181 | |
2182 // if no code - do nothing | |
2183 // compiler needs info | |
2184 if (method().getCodeSize() == 0 || _max_locals + method().getMaxStack() == 0) { | |
2185 fillStackmapProlog(0); | |
2186 fillStackmapEpilog(); | |
2187 return; | |
2188 } | |
2189 // Step 1: Compute all jump targets and their return value | |
2190 if (!_got_error) | |
2191 _rt.computeRetTable(_method); | |
2192 | |
2193 // Step 2: Find all basic blocks and count GC points | |
2194 if (!_got_error) | |
2195 markBBHeadersAndCountGCPoints(); | |
2196 | |
2197 // Step 3: Calculate stack maps | |
2198 if (!_got_error) | |
2199 doInterpretation(); | |
2200 | |
2201 // Step 4:Return results | |
2202 if (!_got_error && reportResults()) | |
2203 reportResult(); | |
2204 | |
2205 if (_got_error) { | |
2206 // We could expand this code to throw somekind of exception (e.g., VerifyException). However, | |
2207 // an exception thrown in this part of the code is likly to mean that we are executing some | |
2208 // illegal bytecodes (that the verifier should have caught if turned on), so we will just exit | |
2209 // with a fatal. | |
2210 throw new RuntimeException("Illegal bytecode sequence encountered while generating interpreter pointer maps - method should be rejected by verifier."); | |
2211 } | |
2212 } | |
2213 | |
2214 // Do a callback on fill_stackmap_for_opcodes for basicblock containing bci | |
2215 public void resultForBasicblock(int bci) { | |
2216 // FIXME: remove | |
2217 // if (TraceNewOopMapGeneration) tty.print_cr("Report result pass for basicblock"); | |
2218 | |
2219 // We now want to report the result of the parse | |
2220 _report_result = true; | |
2221 | |
2222 // Find basicblock and report results | |
2223 BasicBlock bb = getBasicBlockContaining(bci); | |
2224 if (Assert.ASSERTS_ENABLED) { | |
2225 Assert.that(bb.isReachable(), "getting result from unreachable basicblock"); | |
2226 } | |
2227 bb.setChanged(true); | |
2228 interpBB(bb); | |
2229 } | |
2230 | |
2231 // Query | |
2232 public int maxLocals() { return _max_locals; } | |
2233 public Method method() { return _method; } | |
2234 | |
2235 // bool did_rewriting() { return _did_rewriting; } | |
2236 // bool did_relocation() { return _did_relocation; } | |
2237 | |
2238 // static void print_time(); | |
2239 | |
2240 // Monitor query | |
2241 public boolean monitorSafe() { return _monitor_safe; } | |
2242 // Takes as input the bci of a monitorexit bytecode. | |
2243 // Returns the bci of the corresponding monitorenter. | |
2244 // Can only be called safely after computeMap() is run. | |
2245 public int getMonitorMatch(int bci) { | |
2246 if (Assert.ASSERTS_ENABLED) { | |
2247 Assert.that(_monitor_safe, "Attempt to match monitor in broken code."); | |
2248 } | |
2249 | |
2250 // if (TraceNewOopMapGeneration) | |
2251 // tty.print_cr("Report monitor match for bci : %d", bci); | |
2252 | |
2253 // We want to report the line number of the monitorenter. | |
2254 _report_for_exit_bci = bci; | |
2255 _matching_enter_bci = -1; | |
2256 | |
2257 // Find basicblock and report results | |
2258 BasicBlock bb = getBasicBlockContaining(bci); | |
2259 if (bb.isReachable()) { | |
2260 bb.setChanged(true); | |
2261 interpBB(bb); | |
2262 _report_for_exit_bci = -1; | |
2263 if (Assert.ASSERTS_ENABLED) { | |
2264 Assert.that(_matching_enter_bci != -1, "monitor matching invariant"); | |
2265 } | |
2266 } | |
2267 return _matching_enter_bci; | |
2268 } | |
2269 | |
2270 // Returns a Arena allocated object that contains pairing info. | |
2271 // MonitorPairs* get_pairing(Arena *arena); | |
2272 | |
2273 // copies monitor pairing info into area; area_count specifies maximum | |
2274 // possible number of monitor pairs | |
2275 // int copy_pairing(int pair_count, MonitorPairs* pairs); | |
2276 | |
2277 private int bbIndex(BasicBlock bb) { | |
2278 for (int i = 0; i < _basic_blocks.length; i++) { | |
2279 if (_basic_blocks[i] == bb) { | |
2280 return i; | |
2281 } | |
2282 } | |
2283 throw new RuntimeException("Should have found block"); | |
2284 } | |
2285 | |
2286 //---------------------------------------------------------------------- | |
2287 // Specialization methods. Intended use: | |
2288 // - possibleGCPoint must return true for every bci for which the | |
2289 // stackmaps must be returned | |
2290 // - fillStackmapProlog is called just before the result is | |
2291 // reported. The arguments tells the estimated number of gc points | |
2292 // - fillStackmapForOpcodes is called once for each bytecode index | |
2293 // in order (0...code_length-1) | |
2294 // - fillStackmapEpilog is called after all results has been | |
2295 // reported. Note: Since the algorithm does not report stackmaps for | |
2296 // deadcode, fewer gc_points might have been encounted than assumed | |
2297 // during the epilog. It is the responsibility of the subclass to | |
2298 // count the correct number. | |
2299 // - fillInitVars are called once with the result of the init_vars | |
2300 // computation | |
2301 // | |
2302 // All these methods are used during a call to computeMap. Note: | |
2303 // None of the return results are valid after computeMap returns, | |
2304 // since all values are allocated as resource objects. | |
2305 // | |
2306 // All virtual method must be implemented in subclasses | |
2307 public boolean allowRewrites () { return false; } | |
2308 public boolean reportResults () { return true; } | |
2309 public boolean reportInitVars () { return true; } | |
2310 public boolean possibleGCPoint (BytecodeStream bcs) { throw new RuntimeException("ShouldNotReachHere"); } | |
2311 public void fillStackmapProlog (int nofGCPoints) { throw new RuntimeException("ShouldNotReachHere"); } | |
2312 public void fillStackmapEpilog () { throw new RuntimeException("ShouldNotReachHere"); } | |
2313 public void fillStackmapForOpcodes (BytecodeStream bcs, | |
2314 CellTypeStateList vars, | |
2315 CellTypeStateList stack, | |
2316 int stackTop) { throw new RuntimeException("ShouldNotReachHere"); } | |
2317 public void fillInitVars (List/*<Integer>*/ init_vars) { throw new RuntimeException("ShouldNotReachHere"); } | |
2318 } |