Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java @ 3945:8ed53447f690
Merge
author | iveresov |
---|---|
date | Thu, 15 Sep 2011 12:44:09 -0700 |
parents | 6a991dcb52bb |
children | 8150fa46d2ed |
rev | line source |
---|---|
0 | 1 /* |
2426
1d1603768966
7010070: Update all 2010 Oracle-changed OpenJDK files to have the proper copyright dates - second pass
trims
parents:
2177
diff
changeset
|
2 * Copyright (c) 2001, 2011, 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(); |
0 | 616 constantPoolOop cp = method().constants(); |
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 | |
654 TypeArray excps = method().getExceptionTable(); | |
655 for(int i = 0; i < excps.getLength(); i += 4) { | |
656 int handler_pc_idx = i+2; | |
657 markBB(excps.getIntAt(handler_pc_idx), null); | |
658 } | |
659 | |
660 // Then iterate through the code | |
661 BytecodeStream bcs = new BytecodeStream(_method); | |
662 int bytecode; | |
663 | |
664 while( (bytecode = bcs.next()) >= 0) { | |
665 int bci = bcs.bci(); | |
666 | |
667 if (!fellThrough) | |
668 markBB(bci, null); | |
669 | |
670 fellThrough = jumpTargetsDo(bcs, | |
671 new JumpClosure() { | |
672 public void process(GenerateOopMap c, int bcpDelta, int[] data) { | |
673 c.markBB(bcpDelta, data); | |
674 } | |
675 }, | |
676 null); | |
677 | |
678 /* We will also mark successors of jsr's as basic block headers. */ | |
679 switch (bytecode) { | |
680 case Bytecodes._jsr: | |
681 if (Assert.ASSERTS_ENABLED) { | |
682 Assert.that(!fellThrough, "should not happen"); | |
683 } | |
684 markBB(bci + Bytecodes.lengthFor(bytecode), null); | |
685 break; | |
686 case Bytecodes._jsr_w: | |
687 if (Assert.ASSERTS_ENABLED) { | |
688 Assert.that(!fellThrough, "should not happen"); | |
689 } | |
690 markBB(bci + Bytecodes.lengthFor(bytecode), null); | |
691 break; | |
692 } | |
693 | |
694 if (possibleGCPoint(bcs)) | |
695 _gc_points++; | |
696 } | |
697 } | |
698 | |
699 boolean isBBHeader (int bci) { | |
700 return _bb_hdr_bits.at(bci); | |
701 } | |
702 | |
703 int gcPoints () { | |
704 return _gc_points; | |
705 } | |
706 | |
707 int bbCount () { | |
708 return _bb_count; | |
709 } | |
710 | |
711 void setBBMarkBit (int bci) { | |
712 _bb_hdr_bits.atPut(bci, true); | |
713 } | |
714 | |
715 void clear_bbmark_bit (int bci) { | |
716 _bb_hdr_bits.atPut(bci, false); | |
717 } | |
718 | |
719 BasicBlock getBasicBlockAt (int bci) { | |
720 BasicBlock bb = getBasicBlockContaining(bci); | |
721 if (Assert.ASSERTS_ENABLED) { | |
722 Assert.that(bb._bci == bci, "should have found BB"); | |
723 } | |
724 return bb; | |
725 } | |
726 | |
727 BasicBlock getBasicBlockContaining (int bci) { | |
728 BasicBlock[] bbs = _basic_blocks; | |
729 int lo = 0, hi = _bb_count - 1; | |
730 | |
731 while (lo <= hi) { | |
732 int m = (lo + hi) / 2; | |
733 int mbci = bbs[m]._bci; | |
734 int nbci; | |
735 | |
736 if ( m == _bb_count-1) { | |
737 if (Assert.ASSERTS_ENABLED) { | |
738 Assert.that( bci >= mbci && bci < method().getCodeSize(), "sanity check failed"); | |
739 } | |
740 return bbs[m]; | |
741 } else { | |
742 nbci = bbs[m+1]._bci; | |
743 } | |
744 | |
745 if ( mbci <= bci && bci < nbci) { | |
746 return bbs[m]; | |
747 } else if (mbci < bci) { | |
748 lo = m + 1; | |
749 } else { | |
750 if (Assert.ASSERTS_ENABLED) { | |
751 Assert.that(mbci > bci, "sanity check"); | |
752 } | |
753 hi = m - 1; | |
754 } | |
755 } | |
756 | |
757 throw new RuntimeException("should have found BB"); | |
758 } | |
759 | |
760 void interpBB (BasicBlock bb) { | |
761 // We do not want to do anything in case the basic-block has not been initialized. This | |
762 // will happen in the case where there is dead-code hang around in a method. | |
763 if (Assert.ASSERTS_ENABLED) { | |
764 Assert.that(bb.isReachable(), "should be reachable or deadcode exist"); | |
765 } | |
766 restoreState(bb); | |
767 | |
768 BytecodeStream itr = new BytecodeStream(_method); | |
769 | |
770 // Set iterator interval to be the current basicblock | |
771 int lim_bci = nextBBStartPC(bb); | |
772 itr.setInterval(bb._bci, lim_bci); | |
773 | |
774 if (DEBUG) { | |
775 System.err.println("interpBB: method = " + method().getName().asString() + | |
776 method().getSignature().asString() + | |
777 ", BCI interval [" + bb._bci + ", " + lim_bci + ")"); | |
778 { | |
779 System.err.print("Bytecodes:"); | |
780 for (int i = bb._bci; i < lim_bci; i++) { | |
781 System.err.print(" 0x" + Long.toHexString(method().getBytecodeOrBPAt(i))); | |
782 } | |
783 System.err.println(); | |
784 } | |
785 } | |
786 | |
787 if (Assert.ASSERTS_ENABLED) { | |
788 Assert.that(lim_bci != bb._bci, "must be at least one instruction in a basicblock"); | |
789 } | |
790 itr.next(); // read first instruction | |
791 | |
792 // Iterates through all bytecodes except the last in a basic block. | |
793 // We handle the last one special, since there is controlflow change. | |
794 while(itr.nextBCI() < lim_bci && !_got_error) { | |
795 if (_has_exceptions || (_monitor_top != 0)) { | |
796 // We do not need to interpret the results of exceptional | |
797 // continuation from this instruction when the method has no | |
798 // exception handlers and the monitor stack is currently | |
799 // empty. | |
800 doExceptionEdge(itr); | |
801 } | |
802 interp1(itr); | |
803 itr.next(); | |
804 } | |
805 | |
806 // Handle last instruction. | |
807 if (!_got_error) { | |
808 if (Assert.ASSERTS_ENABLED) { | |
809 Assert.that(itr.nextBCI() == lim_bci, "must point to end"); | |
810 } | |
811 if (_has_exceptions || (_monitor_top != 0)) { | |
812 doExceptionEdge(itr); | |
813 } | |
814 interp1(itr); | |
815 | |
816 boolean fall_through = jumpTargetsDo(itr, new JumpClosure() { | |
817 public void process(GenerateOopMap c, int bcpDelta, int[] data) { | |
818 c.mergeState(bcpDelta, data); | |
819 } | |
820 }, null); | |
821 if (_got_error) return; | |
822 | |
823 if (itr.code() == Bytecodes._ret) { | |
824 if (Assert.ASSERTS_ENABLED) { | |
825 Assert.that(!fall_through, "cannot be set if ret instruction"); | |
826 } | |
827 // Automatically handles 'wide' ret indicies | |
828 retJumpTargetsDo(itr, new JumpClosure() { | |
829 public void process(GenerateOopMap c, int bcpDelta, int[] data) { | |
830 c.mergeState(bcpDelta, data); | |
831 } | |
832 }, itr.getIndex(), null); | |
833 } else if (fall_through) { | |
834 // Hit end of BB, but the instr. was a fall-through instruction, | |
835 // so perform transition as if the BB ended in a "jump". | |
836 if (Assert.ASSERTS_ENABLED) { | |
837 Assert.that(lim_bci == _basic_blocks[bbIndex(bb) + 1]._bci, "there must be another bb"); | |
838 } | |
839 mergeStateIntoBB(_basic_blocks[bbIndex(bb) + 1]); | |
840 } | |
841 } | |
842 } | |
843 | |
844 void restoreState (BasicBlock bb) { | |
845 for (int i = 0; i < _state_len; i++) { | |
846 _state.get(i).set(bb._state.get(i)); | |
847 } | |
848 _stack_top = bb._stack_top; | |
849 _monitor_top = bb._monitor_top; | |
850 } | |
851 | |
852 int nextBBStartPC (BasicBlock bb) { | |
853 int bbNum = bbIndex(bb) + 1; | |
854 if (bbNum == _bb_count) | |
855 return (int) method().getCodeSize(); | |
856 | |
857 return _basic_blocks[bbNum]._bci; | |
858 } | |
859 | |
860 void updateBasicBlocks (int bci, int delta) { | |
861 BitMap bbBits = new BitMap((int) (_method.getCodeSize() + delta)); | |
862 for(int k = 0; k < _bb_count; k++) { | |
863 if (_basic_blocks[k]._bci > bci) { | |
864 _basic_blocks[k]._bci += delta; | |
865 _basic_blocks[k]._end_bci += delta; | |
866 } | |
867 bbBits.atPut(_basic_blocks[k]._bci, true); | |
868 } | |
869 _bb_hdr_bits = bbBits; | |
870 } | |
871 | |
872 void markBB(int bci, int[] data) { | |
873 if (Assert.ASSERTS_ENABLED) { | |
874 Assert.that(bci>= 0 && bci < method().getCodeSize(), "index out of bounds"); | |
875 } | |
876 if (isBBHeader(bci)) | |
877 return; | |
878 | |
879 // FIXME: remove | |
880 // if (TraceNewOopMapGeneration) { | |
881 // tty.print_cr("Basicblock#%d begins at: %d", c._bb_count, bci); | |
882 // } | |
883 setBBMarkBit(bci); | |
884 _bb_count++; | |
885 } | |
886 | |
887 // Dead code detection | |
888 void markReachableCode() { | |
889 final int[] change = new int[1]; | |
890 change[0] = 1; | |
891 | |
892 // Mark entry basic block as alive and all exception handlers | |
893 _basic_blocks[0].markAsAlive(); | |
894 TypeArray excps = method().getExceptionTable(); | |
895 for(int i = 0; i < excps.getLength(); i += 4) { | |
896 int handler_pc_idx = i+2; | |
897 BasicBlock bb = getBasicBlockAt(excps.getIntAt(handler_pc_idx)); | |
898 // If block is not already alive (due to multiple exception handlers to same bb), then | |
899 // make it alive | |
900 if (bb.isDead()) | |
901 bb.markAsAlive(); | |
902 } | |
903 | |
904 BytecodeStream bcs = new BytecodeStream(_method); | |
905 | |
906 // Iterate through all basic blocks until we reach a fixpoint | |
907 while (change[0] != 0) { | |
908 change[0] = 0; | |
909 | |
910 for (int i = 0; i < _bb_count; i++) { | |
911 BasicBlock bb = _basic_blocks[i]; | |
912 if (bb.isAlive()) { | |
913 // Position bytecodestream at last bytecode in basicblock | |
914 bcs.setStart(bb._end_bci); | |
915 bcs.next(); | |
916 int bytecode = bcs.code(); | |
917 int bci = bcs.bci(); | |
918 if (Assert.ASSERTS_ENABLED) { | |
919 Assert.that(bci == bb._end_bci, "wrong bci"); | |
920 } | |
921 | |
922 boolean fell_through = jumpTargetsDo(bcs, new JumpClosure() { | |
923 public void process(GenerateOopMap c, int bciDelta, int[] change) { | |
924 c.reachableBasicblock(bciDelta, change); | |
925 } | |
926 }, change); | |
927 | |
928 // We will also mark successors of jsr's as alive. | |
929 switch (bytecode) { | |
930 case Bytecodes._jsr: | |
931 case Bytecodes._jsr_w: | |
932 if (Assert.ASSERTS_ENABLED) { | |
933 Assert.that(!fell_through, "should not happen"); | |
934 } | |
935 reachableBasicblock(bci + Bytecodes.lengthFor(bytecode), change); | |
936 break; | |
937 } | |
938 if (fell_through) { | |
939 // Mark successor as alive | |
940 if (_basic_blocks[i+1].isDead()) { | |
941 _basic_blocks[i+1].markAsAlive(); | |
942 change[0] = 1; | |
943 } | |
944 } | |
945 } | |
946 } | |
947 } | |
948 } | |
949 | |
950 void reachableBasicblock (int bci, int[] data) { | |
951 if (Assert.ASSERTS_ENABLED) { | |
952 Assert.that(bci>= 0 && bci < method().getCodeSize(), "index out of bounds"); | |
953 } | |
954 BasicBlock bb = getBasicBlockAt(bci); | |
955 if (bb.isDead()) { | |
956 bb.markAsAlive(); | |
957 data[0] = 1; // Mark basicblock as changed | |
958 } | |
959 } | |
960 | |
961 // Interpretation methods (primary) | |
962 void doInterpretation () { | |
963 // "i" is just for debugging, so we can detect cases where this loop is | |
964 // iterated more than once. | |
965 int i = 0; | |
966 do { | |
967 // FIXME: remove | |
968 // if (TraceNewOopMapGeneration) { | |
969 // tty.print("\n\nIteration #%d of do_interpretation loop, method:\n", i); | |
970 // method().print_name(tty); | |
971 // tty.print("\n\n"); | |
972 // } | |
973 _conflict = false; | |
974 _monitor_safe = true; | |
975 // init_state is now called from init_basic_blocks. The length of a | |
976 // state vector cannot be determined until we have made a pass through | |
977 // the bytecodes counting the possible monitor entries. | |
978 if (!_got_error) initBasicBlocks(); | |
979 if (!_got_error) setupMethodEntryState(); | |
980 if (!_got_error) interpAll(); | |
981 if (!_got_error) rewriteRefvalConflicts(); | |
982 i++; | |
983 } while (_conflict && !_got_error); | |
984 } | |
985 | |
986 void initBasicBlocks () { | |
987 // Note: Could consider reserving only the needed space for each BB's state | |
988 // (entry stack may not be of maximal height for every basic block). | |
989 // But cumbersome since we don't know the stack heights yet. (Nor the | |
990 // monitor stack heights...) | |
991 | |
992 _basic_blocks = new BasicBlock[_bb_count]; | |
993 for (int i = 0; i < _bb_count; i++) { | |
994 _basic_blocks[i] = new BasicBlock(); | |
995 } | |
996 | |
997 // Make a pass through the bytecodes. Count the number of monitorenters. | |
998 // This can be used an upper bound on the monitor stack depth in programs | |
999 // which obey stack discipline with their monitor usage. Initialize the | |
1000 // known information about basic blocks. | |
1001 BytecodeStream j = new BytecodeStream(_method); | |
1002 int bytecode; | |
1003 | |
1004 int bbNo = 0; | |
1005 int monitor_count = 0; | |
1006 int prev_bci = -1; | |
1007 while( (bytecode = j.next()) >= 0) { | |
1008 if (j.code() == Bytecodes._monitorenter) { | |
1009 monitor_count++; | |
1010 } | |
1011 | |
1012 int bci = j.bci(); | |
1013 if (isBBHeader(bci)) { | |
1014 // Initialize the basicblock structure | |
1015 BasicBlock bb = _basic_blocks[bbNo]; | |
1016 bb._bci = bci; | |
1017 bb._max_locals = _max_locals; | |
1018 bb._max_stack = _max_stack; | |
1019 bb.setChanged(false); | |
1020 bb._stack_top = BasicBlock._dead_basic_block; // Initialize all basicblocks are dead. | |
1021 bb._monitor_top = bad_monitors; | |
1022 | |
1023 if (bbNo > 0) { | |
1024 _basic_blocks[bbNo - 1]._end_bci = prev_bci; | |
1025 } | |
1026 | |
1027 bbNo++; | |
1028 } | |
1029 // Remember prevous bci. | |
1030 prev_bci = bci; | |
1031 } | |
1032 // Set | |
1033 _basic_blocks[bbNo-1]._end_bci = prev_bci; | |
1034 | |
1035 _max_monitors = monitor_count; | |
1036 | |
1037 // Now that we have a bound on the depth of the monitor stack, we can | |
1038 // initialize the CellTypeState-related information. | |
1039 initState(); | |
1040 | |
1041 // We allocate space for all state-vectors for all basicblocks in one huge chuck. | |
1042 // Then in the next part of the code, we set a pointer in each _basic_block that | |
1043 // points to each piece. | |
1044 CellTypeStateList basicBlockState = new CellTypeStateList(bbNo * _state_len); | |
1045 | |
1046 // Make a pass over the basicblocks and assign their state vectors. | |
1047 for (int blockNum=0; blockNum < bbNo; blockNum++) { | |
1048 BasicBlock bb = _basic_blocks[blockNum]; | |
1049 bb._state = basicBlockState.subList(blockNum * _state_len, (blockNum + 1) * _state_len); | |
1050 | |
1051 if (Assert.ASSERTS_ENABLED) { | |
1052 if (blockNum + 1 < bbNo) { | |
1053 int bc_len = Bytecodes.javaLengthAt(_method, bb._end_bci); | |
1054 Assert.that(bb._end_bci + bc_len == _basic_blocks[blockNum + 1]._bci, | |
1055 "unmatched bci info in basicblock"); | |
1056 } | |
1057 } | |
1058 } | |
1059 if (Assert.ASSERTS_ENABLED) { | |
1060 BasicBlock bb = _basic_blocks[bbNo-1]; | |
1061 int bc_len = Bytecodes.javaLengthAt(_method, bb._end_bci); | |
1062 Assert.that(bb._end_bci + bc_len == _method.getCodeSize(), "wrong end bci"); | |
1063 } | |
1064 | |
1065 // Check that the correct number of basicblocks was found | |
1066 if (bbNo !=_bb_count) { | |
1067 if (bbNo < _bb_count) { | |
1068 throw new RuntimeException("jump into the middle of instruction?"); | |
1069 } else { | |
1070 throw new RuntimeException("extra basic blocks - should not happen?"); | |
1071 } | |
1072 } | |
1073 | |
1074 // Mark all alive blocks | |
1075 markReachableCode(); | |
1076 } | |
1077 | |
1078 void setupMethodEntryState () { | |
1079 // Initialize all locals to 'uninit' and set stack-height to 0 | |
1080 makeContextUninitialized(); | |
1081 | |
1082 // Initialize CellState type of arguments | |
1083 methodsigToEffect(method().getSignature(), method().isStatic(), vars()); | |
1084 | |
1085 // If some references must be pre-assigned to null, then set that up | |
1086 initializeVars(); | |
1087 | |
1088 // This is the start state | |
1089 mergeStateIntoBB(_basic_blocks[0]); | |
1090 | |
1091 if (Assert.ASSERTS_ENABLED) { | |
1092 Assert.that(_basic_blocks[0].changed(), "we are not getting off the ground"); | |
1093 } | |
1094 } | |
1095 | |
1096 void interpAll () { | |
1097 boolean change = true; | |
1098 | |
1099 while (change && !_got_error) { | |
1100 change = false; | |
1101 for (int i = 0; i < _bb_count && !_got_error; i++) { | |
1102 BasicBlock bb = _basic_blocks[i]; | |
1103 if (bb.changed()) { | |
1104 if (_got_error) return; | |
1105 change = true; | |
1106 bb.setChanged(false); | |
1107 interpBB(bb); | |
1108 } | |
1109 } | |
1110 } | |
1111 } | |
1112 | |
1113 // | |
1114 // Interpretation methods (secondary) | |
1115 // | |
1116 | |
1117 /** Sets the current state to be the state after executing the | |
1118 current instruction, starting in the current state. */ | |
1119 void interp1 (BytecodeStream itr) { | |
1120 if (DEBUG) { | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1121 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
|
1122 printCurrentState(System.err, itr, false); |
0 | 1123 } |
1124 | |
1125 // if (TraceNewOopMapGeneration) { | |
1126 // print_current_state(tty, itr, TraceNewOopMapGenerationDetailed); | |
1127 // } | |
1128 | |
1129 // Should we report the results? Result is reported *before* the | |
1130 // instruction at the current bci is executed. However, not for | |
1131 // calls. For calls we do not want to include the arguments, so we | |
1132 // postpone the reporting until they have been popped (in method | |
1133 // ppl). | |
1134 if (_report_result == true) { | |
1135 switch(itr.code()) { | |
1136 case Bytecodes._invokevirtual: | |
1137 case Bytecodes._invokespecial: | |
1138 case Bytecodes._invokestatic: | |
1139 case Bytecodes._invokeinterface: | |
1602 | 1140 case Bytecodes._invokedynamic: |
0 | 1141 _itr_send = itr; |
1142 _report_result_for_send = true; | |
1143 break; | |
1144 default: | |
1145 fillStackmapForOpcodes(itr, vars(), stack(), _stack_top); | |
1146 break; | |
1147 } | |
1148 } | |
1149 | |
1150 // abstract interpretation of current opcode | |
1151 switch(itr.code()) { | |
1152 case Bytecodes._nop: break; | |
1153 case Bytecodes._goto: break; | |
1154 case Bytecodes._goto_w: break; | |
1155 case Bytecodes._iinc: break; | |
1156 case Bytecodes._return: doReturnMonitorCheck(); | |
1157 break; | |
1158 | |
1159 case Bytecodes._aconst_null: | |
1160 case Bytecodes._new: ppush1(CellTypeState.makeLineRef(itr.bci())); | |
1161 break; | |
1162 | |
1163 case Bytecodes._iconst_m1: | |
1164 case Bytecodes._iconst_0: | |
1165 case Bytecodes._iconst_1: | |
1166 case Bytecodes._iconst_2: | |
1167 case Bytecodes._iconst_3: | |
1168 case Bytecodes._iconst_4: | |
1169 case Bytecodes._iconst_5: | |
1170 case Bytecodes._fconst_0: | |
1171 case Bytecodes._fconst_1: | |
1172 case Bytecodes._fconst_2: | |
1173 case Bytecodes._bipush: | |
1174 case Bytecodes._sipush: ppush1(valCTS); break; | |
1175 | |
1176 case Bytecodes._lconst_0: | |
1177 case Bytecodes._lconst_1: | |
1178 case Bytecodes._dconst_0: | |
1179 case Bytecodes._dconst_1: ppush(vvCTS); break; | |
1180 | |
1181 case Bytecodes._ldc2_w: ppush(vvCTS); break; | |
1182 | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1183 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
|
1184 case Bytecodes._ldc_w: doLdc(itr.bci()); break; |
0 | 1185 |
1186 case Bytecodes._iload: | |
1187 case Bytecodes._fload: ppload(vCTS, itr.getIndex()); break; | |
1188 | |
1189 case Bytecodes._lload: | |
1190 case Bytecodes._dload: ppload(vvCTS,itr.getIndex()); break; | |
1191 | |
1192 case Bytecodes._aload: ppload(rCTS, itr.getIndex()); break; | |
1193 | |
1194 case Bytecodes._iload_0: | |
1195 case Bytecodes._fload_0: ppload(vCTS, 0); break; | |
1196 case Bytecodes._iload_1: | |
1197 case Bytecodes._fload_1: ppload(vCTS, 1); break; | |
1198 case Bytecodes._iload_2: | |
1199 case Bytecodes._fload_2: ppload(vCTS, 2); break; | |
1200 case Bytecodes._iload_3: | |
1201 case Bytecodes._fload_3: ppload(vCTS, 3); break; | |
1202 | |
1203 case Bytecodes._lload_0: | |
1204 case Bytecodes._dload_0: ppload(vvCTS, 0); break; | |
1205 case Bytecodes._lload_1: | |
1206 case Bytecodes._dload_1: ppload(vvCTS, 1); break; | |
1207 case Bytecodes._lload_2: | |
1208 case Bytecodes._dload_2: ppload(vvCTS, 2); break; | |
1209 case Bytecodes._lload_3: | |
1210 case Bytecodes._dload_3: ppload(vvCTS, 3); break; | |
1211 | |
1212 case Bytecodes._aload_0: ppload(rCTS, 0); break; | |
1213 case Bytecodes._aload_1: ppload(rCTS, 1); break; | |
1214 case Bytecodes._aload_2: ppload(rCTS, 2); break; | |
1215 case Bytecodes._aload_3: ppload(rCTS, 3); break; | |
1216 | |
1217 case Bytecodes._iaload: | |
1218 case Bytecodes._faload: | |
1219 case Bytecodes._baload: | |
1220 case Bytecodes._caload: | |
1221 case Bytecodes._saload: pp(vrCTS, vCTS); break; | |
1222 | |
1223 case Bytecodes._laload: pp(vrCTS, vvCTS); break; | |
1224 case Bytecodes._daload: pp(vrCTS, vvCTS); break; | |
1225 | |
1226 case Bytecodes._aaload: ppNewRef(vrCTS, itr.bci()); break; | |
1227 | |
1228 case Bytecodes._istore: | |
1229 case Bytecodes._fstore: ppstore(vCTS, itr.getIndex()); break; | |
1230 | |
1231 case Bytecodes._lstore: | |
1232 case Bytecodes._dstore: ppstore(vvCTS, itr.getIndex()); break; | |
1233 | |
1234 case Bytecodes._astore: doAstore(itr.getIndex()); break; | |
1235 | |
1236 case Bytecodes._istore_0: | |
1237 case Bytecodes._fstore_0: ppstore(vCTS, 0); break; | |
1238 case Bytecodes._istore_1: | |
1239 case Bytecodes._fstore_1: ppstore(vCTS, 1); break; | |
1240 case Bytecodes._istore_2: | |
1241 case Bytecodes._fstore_2: ppstore(vCTS, 2); break; | |
1242 case Bytecodes._istore_3: | |
1243 case Bytecodes._fstore_3: ppstore(vCTS, 3); break; | |
1244 | |
1245 case Bytecodes._lstore_0: | |
1246 case Bytecodes._dstore_0: ppstore(vvCTS, 0); break; | |
1247 case Bytecodes._lstore_1: | |
1248 case Bytecodes._dstore_1: ppstore(vvCTS, 1); break; | |
1249 case Bytecodes._lstore_2: | |
1250 case Bytecodes._dstore_2: ppstore(vvCTS, 2); break; | |
1251 case Bytecodes._lstore_3: | |
1252 case Bytecodes._dstore_3: ppstore(vvCTS, 3); break; | |
1253 | |
1254 case Bytecodes._astore_0: doAstore(0); break; | |
1255 case Bytecodes._astore_1: doAstore(1); break; | |
1256 case Bytecodes._astore_2: doAstore(2); break; | |
1257 case Bytecodes._astore_3: doAstore(3); break; | |
1258 | |
1259 case Bytecodes._iastore: | |
1260 case Bytecodes._fastore: | |
1261 case Bytecodes._bastore: | |
1262 case Bytecodes._castore: | |
1263 case Bytecodes._sastore: ppop(vvrCTS); break; | |
1264 case Bytecodes._lastore: | |
1265 case Bytecodes._dastore: ppop(vvvrCTS); break; | |
1266 case Bytecodes._aastore: ppop(rvrCTS); break; | |
1267 | |
1268 case Bytecodes._pop: ppopAny(1); break; | |
1269 case Bytecodes._pop2: ppopAny(2); break; | |
1270 | |
1271 case Bytecodes._dup: ppdupswap(1, "11"); break; | |
1272 case Bytecodes._dup_x1: ppdupswap(2, "121"); break; | |
1273 case Bytecodes._dup_x2: ppdupswap(3, "1321"); break; | |
1274 case Bytecodes._dup2: ppdupswap(2, "2121"); break; | |
1275 case Bytecodes._dup2_x1: ppdupswap(3, "21321"); break; | |
1276 case Bytecodes._dup2_x2: ppdupswap(4, "214321"); break; | |
1277 case Bytecodes._swap: ppdupswap(2, "12"); break; | |
1278 | |
1279 case Bytecodes._iadd: | |
1280 case Bytecodes._fadd: | |
1281 case Bytecodes._isub: | |
1282 case Bytecodes._fsub: | |
1283 case Bytecodes._imul: | |
1284 case Bytecodes._fmul: | |
1285 case Bytecodes._idiv: | |
1286 case Bytecodes._fdiv: | |
1287 case Bytecodes._irem: | |
1288 case Bytecodes._frem: | |
1289 case Bytecodes._ishl: | |
1290 case Bytecodes._ishr: | |
1291 case Bytecodes._iushr: | |
1292 case Bytecodes._iand: | |
1293 case Bytecodes._ior: | |
1294 case Bytecodes._ixor: | |
1295 case Bytecodes._l2f: | |
1296 case Bytecodes._l2i: | |
1297 case Bytecodes._d2f: | |
1298 case Bytecodes._d2i: | |
1299 case Bytecodes._fcmpl: | |
1300 case Bytecodes._fcmpg: pp(vvCTS, vCTS); break; | |
1301 | |
1302 case Bytecodes._ladd: | |
1303 case Bytecodes._dadd: | |
1304 case Bytecodes._lsub: | |
1305 case Bytecodes._dsub: | |
1306 case Bytecodes._lmul: | |
1307 case Bytecodes._dmul: | |
1308 case Bytecodes._ldiv: | |
1309 case Bytecodes._ddiv: | |
1310 case Bytecodes._lrem: | |
1311 case Bytecodes._drem: | |
1312 case Bytecodes._land: | |
1313 case Bytecodes._lor: | |
1314 case Bytecodes._lxor: pp(vvvvCTS, vvCTS); break; | |
1315 | |
1316 case Bytecodes._ineg: | |
1317 case Bytecodes._fneg: | |
1318 case Bytecodes._i2f: | |
1319 case Bytecodes._f2i: | |
1320 case Bytecodes._i2c: | |
1321 case Bytecodes._i2s: | |
1322 case Bytecodes._i2b: pp(vCTS, vCTS); break; | |
1323 | |
1324 case Bytecodes._lneg: | |
1325 case Bytecodes._dneg: | |
1326 case Bytecodes._l2d: | |
1327 case Bytecodes._d2l: pp(vvCTS, vvCTS); break; | |
1328 | |
1329 case Bytecodes._lshl: | |
1330 case Bytecodes._lshr: | |
1331 case Bytecodes._lushr: pp(vvvCTS, vvCTS); break; | |
1332 | |
1333 case Bytecodes._i2l: | |
1334 case Bytecodes._i2d: | |
1335 case Bytecodes._f2l: | |
1336 case Bytecodes._f2d: pp(vCTS, vvCTS); break; | |
1337 | |
1338 case Bytecodes._lcmp: pp(vvvvCTS, vCTS); break; | |
1339 case Bytecodes._dcmpl: | |
1340 case Bytecodes._dcmpg: pp(vvvvCTS, vCTS); break; | |
1341 | |
1342 case Bytecodes._ifeq: | |
1343 case Bytecodes._ifne: | |
1344 case Bytecodes._iflt: | |
1345 case Bytecodes._ifge: | |
1346 case Bytecodes._ifgt: | |
1347 case Bytecodes._ifle: | |
1348 case Bytecodes._tableswitch: ppop1(valCTS); | |
1349 break; | |
1350 case Bytecodes._ireturn: | |
1351 case Bytecodes._freturn: doReturnMonitorCheck(); | |
1352 ppop1(valCTS); | |
1353 break; | |
1354 case Bytecodes._if_icmpeq: | |
1355 case Bytecodes._if_icmpne: | |
1356 case Bytecodes._if_icmplt: | |
1357 case Bytecodes._if_icmpge: | |
1358 case Bytecodes._if_icmpgt: | |
1359 case Bytecodes._if_icmple: ppop(vvCTS); | |
1360 break; | |
1361 | |
1362 case Bytecodes._lreturn: doReturnMonitorCheck(); | |
1363 ppop(vvCTS); | |
1364 break; | |
1365 | |
1366 case Bytecodes._dreturn: doReturnMonitorCheck(); | |
1367 ppop(vvCTS); | |
1368 break; | |
1369 | |
1370 case Bytecodes._if_acmpeq: | |
1371 case Bytecodes._if_acmpne: ppop(rrCTS); break; | |
1372 | |
1373 case Bytecodes._jsr: doJsr(itr.dest()); break; | |
1374 case Bytecodes._jsr_w: doJsr(itr.dest_w()); break; | |
1375 | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1376 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
|
1377 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
|
1378 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
|
1379 case Bytecodes._putfield: doField(false, false, itr.getIndexU2Cpcache(), itr.bci()); break; |
0 | 1380 |
1381 case Bytecodes._invokevirtual: | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1382 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
|
1383 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
|
1384 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
|
1385 case Bytecodes._invokeinterface: doMethod(false, true, itr.getIndexU2Cpcache(), itr.bci()); break; |
0 | 1386 case Bytecodes._newarray: |
1387 case Bytecodes._anewarray: ppNewRef(vCTS, itr.bci()); break; | |
1388 case Bytecodes._checkcast: doCheckcast(); break; | |
1389 case Bytecodes._arraylength: | |
1390 case Bytecodes._instanceof: pp(rCTS, vCTS); break; | |
1391 case Bytecodes._monitorenter: doMonitorenter(itr.bci()); break; | |
1392 case Bytecodes._monitorexit: doMonitorexit(itr.bci()); break; | |
1393 | |
1394 case Bytecodes._athrow: // handled by do_exception_edge() BUT ... | |
1395 // vlh(apple): doExceptionEdge() does not get | |
1396 // called if method has no exception handlers | |
1397 if ((!_has_exceptions) && (_monitor_top > 0)) { | |
1398 _monitor_safe = false; | |
1399 } | |
1400 break; | |
1401 | |
1402 case Bytecodes._areturn: doReturnMonitorCheck(); | |
1403 ppop1(refCTS); | |
1404 break; | |
1405 case Bytecodes._ifnull: | |
1406 case Bytecodes._ifnonnull: ppop1(refCTS); break; | |
1407 case Bytecodes._multianewarray: doMultianewarray(itr.codeAt(itr.bci() + 3), itr.bci()); break; | |
1408 | |
1409 case Bytecodes._wide: throw new RuntimeException("Iterator should skip this bytecode"); | |
1410 case Bytecodes._ret: break; | |
1411 | |
1412 // Java opcodes | |
1413 case Bytecodes._fast_aaccess_0: ppNewRef(rCTS, itr.bci()); break; // Pair bytecode for (aload_0, _fast_agetfield) | |
1414 | |
1415 case Bytecodes._fast_iaccess_0: ppush1(valCTS); break; // Pair bytecode for (aload_0, _fast_igetfield) | |
1416 | |
1417 case Bytecodes._fast_igetfield: pp(rCTS, vCTS); break; | |
1418 | |
1419 case Bytecodes._fast_agetfield: ppNewRef(rCTS, itr.bci()); break; | |
1420 | |
1421 case Bytecodes._fast_aload_0: ppload(rCTS, 0); break; | |
1422 | |
1423 case Bytecodes._lookupswitch: | |
1424 case Bytecodes._fast_linearswitch: | |
1425 case Bytecodes._fast_binaryswitch: ppop1(valCTS); break; | |
1426 | |
1427 default: | |
1428 throw new RuntimeException("unexpected opcode: " + itr.code()); | |
1429 } | |
1430 } | |
1431 | |
1432 void doExceptionEdge (BytecodeStream itr) { | |
1433 // Only check exception edge, if bytecode can trap | |
1434 if (!Bytecodes.canTrap(itr.code())) return; | |
1435 switch (itr.code()) { | |
1436 case Bytecodes._aload_0: | |
1437 case Bytecodes._fast_aload_0: | |
1438 // These bytecodes can trap for rewriting. We need to assume that | |
1439 // they do not throw exceptions to make the monitor analysis work. | |
1440 return; | |
1441 | |
1442 case Bytecodes._ireturn: | |
1443 case Bytecodes._lreturn: | |
1444 case Bytecodes._freturn: | |
1445 case Bytecodes._dreturn: | |
1446 case Bytecodes._areturn: | |
1447 case Bytecodes._return: | |
1448 // If the monitor stack height is not zero when we leave the method, | |
1449 // then we are either exiting with a non-empty stack or we have | |
1450 // found monitor trouble earlier in our analysis. In either case, | |
1451 // assume an exception could be taken here. | |
1452 if (_monitor_top == 0) { | |
1453 return; | |
1454 } | |
1455 break; | |
1456 | |
1457 case Bytecodes._monitorexit: | |
1458 // If the monitor stack height is bad_monitors, then we have detected a | |
1459 // monitor matching problem earlier in the analysis. If the | |
1460 // monitor stack height is 0, we are about to pop a monitor | |
1461 // off of an empty stack. In either case, the bytecode | |
1462 // could throw an exception. | |
1463 if (_monitor_top != bad_monitors && _monitor_top != 0) { | |
1464 return; | |
1465 } | |
1466 break; | |
1467 } | |
1468 | |
1469 if (_has_exceptions) { | |
1470 int bci = itr.bci(); | |
1471 TypeArray exct = method().getExceptionTable(); | |
1472 for(int i = 0; i< exct.getLength(); i+=4) { | |
1473 int start_pc = exct.getIntAt(i); | |
1474 int end_pc = exct.getIntAt(i+1); | |
1475 int handler_pc = exct.getIntAt(i+2); | |
1476 int catch_type = exct.getIntAt(i+3); | |
1477 | |
1478 if (start_pc <= bci && bci < end_pc) { | |
1479 BasicBlock excBB = getBasicBlockAt(handler_pc); | |
1480 CellTypeStateList excStk = excBB.stack(); | |
1481 CellTypeStateList cOpStck = stack(); | |
1482 CellTypeState cOpStck_0 = cOpStck.get(0).copy(); | |
1483 int cOpStackTop = _stack_top; | |
1484 | |
1485 // Exception stacks are always the same. | |
1486 if (Assert.ASSERTS_ENABLED) { | |
1487 Assert.that(method().getMaxStack() > 0, "sanity check"); | |
1488 } | |
1489 | |
1490 // We remembered the size and first element of "cOpStck" | |
1491 // above; now we temporarily set them to the appropriate | |
1492 // values for an exception handler. | |
1493 cOpStck.get(0).set(CellTypeState.makeSlotRef(_max_locals)); | |
1494 _stack_top = 1; | |
1495 | |
1496 mergeStateIntoBB(excBB); | |
1497 | |
1498 // Now undo the temporary change. | |
1499 cOpStck.get(0).set(cOpStck_0); | |
1500 _stack_top = cOpStackTop; | |
1501 | |
1502 // If this is a "catch all" handler, then we do not need to | |
1503 // consider any additional handlers. | |
1504 if (catch_type == 0) { | |
1505 return; | |
1506 } | |
1507 } | |
1508 } | |
1509 } | |
1510 | |
1511 // It is possible that none of the exception handlers would have caught | |
1512 // the exception. In this case, we will exit the method. We must | |
1513 // ensure that the monitor stack is empty in this case. | |
1514 if (_monitor_top == 0) { | |
1515 return; | |
1516 } | |
1517 | |
1518 // We pessimistically assume that this exception can escape the | |
1519 // method. (It is possible that it will always be caught, but | |
1520 // we don't care to analyse the types of the catch clauses.) | |
1521 | |
1522 // We don't set _monitor_top to bad_monitors because there are no successors | |
1523 // to this exceptional exit. | |
1524 | |
1525 if (TraceMonitorMismatch && _monitor_safe) { | |
1526 // We check _monitor_safe so that we only report the first mismatched | |
1527 // exceptional exit. | |
1528 reportMonitorMismatch("non-empty monitor stack at exceptional exit"); | |
1529 } | |
1530 _monitor_safe = false; | |
1531 } | |
1532 | |
1533 void checkType (CellTypeState expected, CellTypeState actual) { | |
1534 if (!expected.equalKind(actual)) { | |
1535 throw new RuntimeException("wrong type on stack (found: " + | |
1536 actual.toChar() + " expected: " + | |
1537 expected.toChar() + ")"); | |
1538 } | |
1539 } | |
1540 | |
1541 void ppstore (CellTypeState[] in, int loc_no) { | |
1542 for (int i = 0; i < in.length && !in[i].equal(CellTypeState.bottom); i++) { | |
1543 CellTypeState expected = in[i]; | |
1544 CellTypeState actual = pop(); | |
1545 checkType(expected, actual); | |
1546 if (Assert.ASSERTS_ENABLED) { | |
1547 Assert.that(loc_no >= 0, "sanity check"); | |
1548 } | |
1549 setVar(loc_no++, actual); | |
1550 } | |
1551 } | |
1552 | |
1553 void ppload (CellTypeState[] out, int loc_no) { | |
1554 for (int i = 0; i < out.length && !out[i].equal(CellTypeState.bottom); i++) { | |
1555 CellTypeState out1 = out[i]; | |
1556 CellTypeState vcts = getVar(loc_no); | |
1557 if (Assert.ASSERTS_ENABLED) { | |
1558 Assert.that(out1.canBeReference() || out1.canBeValue(), | |
1559 "can only load refs. and values."); | |
1560 } | |
1561 if (out1.isReference()) { | |
1562 if (Assert.ASSERTS_ENABLED) { | |
1563 Assert.that(loc_no>=0, "sanity check"); | |
1564 } | |
1565 if (!vcts.isReference()) { | |
1566 // We were asked to push a reference, but the type of the | |
1567 // variable can be something else | |
1568 _conflict = true; | |
1569 if (vcts.canBeUninit()) { | |
1570 // It is a ref-uninit conflict (at least). If there are other | |
1571 // problems, we'll get them in the next round | |
1572 addToRefInitSet(loc_no); | |
1573 vcts = out1; | |
1574 } else { | |
1575 // It wasn't a ref-uninit conflict. So must be a | |
1576 // ref-val or ref-pc conflict. Split the variable. | |
1577 recordRefvalConflict(loc_no); | |
1578 vcts = out1; | |
1579 } | |
1580 push(out1); // recover... | |
1581 } else { | |
1582 push(vcts); // preserve reference. | |
1583 } | |
1584 // Otherwise it is a conflict, but one that verification would | |
1585 // have caught if illegal. In particular, it can't be a topCTS | |
1586 // resulting from mergeing two difference pcCTS's since the verifier | |
1587 // would have rejected any use of such a merge. | |
1588 } else { | |
1589 push(out1); // handle val/init conflict | |
1590 } | |
1591 loc_no++; | |
1592 } | |
1593 } | |
1594 | |
1595 void ppush1 (CellTypeState in) { | |
1596 if (Assert.ASSERTS_ENABLED) { | |
1597 Assert.that(in.isReference() | in.isValue(), "sanity check"); | |
1598 } | |
1599 if (DEBUG) { | |
1600 System.err.println(" - pushing " + in.toChar()); | |
1601 } | |
1602 push(in); | |
1603 } | |
1604 | |
1605 void ppush (CellTypeState[] in) { | |
1606 for (int i = 0; i < in.length && !in[i].equal(CellTypeState.bottom); i++) { | |
1607 ppush1(in[i]); | |
1608 } | |
1609 } | |
1610 | |
1611 void ppush (CellTypeStateList in) { | |
1612 for (int i = 0; i < in.size() && !in.get(i).equal(CellTypeState.bottom); i++) { | |
1613 ppush1(in.get(i)); | |
1614 } | |
1615 } | |
1616 | |
1617 void ppop1 (CellTypeState out) { | |
1618 CellTypeState actual = pop(); | |
1619 if (DEBUG) { | |
1620 System.err.println(" - popping " + actual.toChar() + ", expecting " + out.toChar()); | |
1621 } | |
1622 checkType(out, actual); | |
1623 } | |
1624 | |
1625 void ppop (CellTypeState[] out) { | |
1626 for (int i = 0; i < out.length && !out[i].equal(CellTypeState.bottom); i++) { | |
1627 ppop1(out[i]); | |
1628 } | |
1629 } | |
1630 | |
1631 void ppopAny (int poplen) { | |
1632 if (_stack_top >= poplen) { | |
1633 _stack_top -= poplen; | |
1634 } else { | |
1635 throw new RuntimeException("stack underflow"); | |
1636 } | |
1637 } | |
1638 | |
1639 void pp (CellTypeState[] in, CellTypeState[] out) { | |
1640 ppop(in); | |
1641 ppush(out); | |
1642 } | |
1643 | |
1644 void ppNewRef (CellTypeState[] in, int bci) { | |
1645 ppop(in); | |
1646 ppush1(CellTypeState.makeLineRef(bci)); | |
1647 } | |
1648 | |
1649 void ppdupswap (int poplen, String out) { | |
1650 CellTypeState[] actual = new CellTypeState[5]; | |
1651 Assert.that(poplen < 5, "this must be less than length of actual vector"); | |
1652 | |
1653 // pop all arguments | |
1654 for(int i = 0; i < poplen; i++) actual[i] = pop(); | |
1655 | |
1656 // put them back | |
1657 for (int i = 0; i < out.length(); i++) { | |
1658 char push_ch = out.charAt(i); | |
1659 int idx = push_ch - '1'; | |
1660 if (Assert.ASSERTS_ENABLED) { | |
1661 Assert.that(idx >= 0 && idx < poplen, "wrong arguments"); | |
1662 } | |
1663 push(actual[idx]); | |
1664 } | |
1665 } | |
1666 | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1667 void doLdc (int bci) { |
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1668 BytecodeLoadConstant ldc = BytecodeLoadConstant.at(_method, bci); |
0 | 1669 ConstantPool cp = method().getConstants(); |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1670 BasicType bt = ldc.resultType(); |
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1671 CellTypeState cts = (bt == BasicType.T_OBJECT) ? CellTypeState.makeLineRef(bci) : valCTS; |
0 | 1672 ppush1(cts); |
1673 } | |
1674 | |
1675 void doAstore (int idx) { | |
1676 CellTypeState r_or_p = pop(); | |
1677 if (!r_or_p.isAddress() && !r_or_p.isReference()) { | |
1678 // We actually expected ref or pc, but we only report that we expected a ref. It does not | |
1679 // really matter (at least for now) | |
1680 throw new RuntimeException("wrong type on stack (found: " + | |
1681 r_or_p.toChar() + ", expected: {pr})"); | |
1682 } | |
1683 setVar(idx, r_or_p); | |
1684 } | |
1685 | |
1686 void doJsr (int targBCI) { | |
1687 push(CellTypeState.makeAddr(targBCI)); | |
1688 } | |
1689 | |
1690 void doField (boolean is_get, boolean is_static, int idx, int bci) { | |
1691 // Dig up signature for field in constant pool | |
1692 ConstantPool cp = method().getConstants(); | |
1693 int nameAndTypeIdx = cp.getNameAndTypeRefIndexAt(idx); | |
1694 int signatureIdx = cp.getSignatureRefIndexAt(nameAndTypeIdx); | |
1695 Symbol signature = cp.getSymbolAt(signatureIdx); | |
1696 | |
1697 if (DEBUG) { | |
1698 System.err.println("doField: signature = " + signature.asString() + ", idx = " + idx + | |
1699 ", nameAndTypeIdx = " + nameAndTypeIdx + ", signatureIdx = " + signatureIdx + ", bci = " + bci); | |
1700 } | |
1701 | |
1702 // Parse signature (espcially simple for fields) | |
1703 // The signature is UFT8 encoded, but the first char is always ASCII for signatures. | |
1704 char sigch = (char) signature.getByteAt(0); | |
1705 CellTypeState[] temp = new CellTypeState[4]; | |
1706 CellTypeState[] eff = sigcharToEffect(sigch, bci, temp); | |
1707 | |
1708 CellTypeState[] in = new CellTypeState[4]; | |
1709 CellTypeState[] out; | |
1710 int i = 0; | |
1711 | |
1712 if (is_get) { | |
1713 out = eff; | |
1714 } else { | |
1715 out = epsilonCTS; | |
1716 i = copyCTS(in, eff); | |
1717 } | |
1718 if (!is_static) in[i++] = CellTypeState.ref; | |
1719 in[i] = CellTypeState.bottom; | |
1720 if (Assert.ASSERTS_ENABLED) { | |
1721 Assert.that(i<=3, "sanity check"); | |
1722 } | |
1723 pp(in, out); | |
1724 } | |
1725 | |
1726 void doMethod (boolean is_static, boolean is_interface, int idx, int bci) { | |
1727 // Dig up signature for field in constant pool | |
1728 ConstantPool cp = _method.getConstants(); | |
3838
6a991dcb52bb
7012081: JSR 292: SA-JDI can't read MH/MT/Indy ConstantPool entries
never
parents:
2426
diff
changeset
|
1729 Symbol signature = cp.getSignatureRefAt(idx); |
0 | 1730 |
1731 // Parse method signature | |
1732 CellTypeStateList out = new CellTypeStateList(4); | |
1733 CellTypeStateList in = new CellTypeStateList(MAXARGSIZE+1); // Includes result | |
1734 ComputeCallStack cse = new ComputeCallStack(signature); | |
1735 | |
1736 // Compute return type | |
1737 int res_length = cse.computeForReturntype(out); | |
1738 | |
1739 // Temporary hack. | |
1740 if (out.get(0).equal(CellTypeState.ref) && out.get(1).equal(CellTypeState.bottom)) { | |
1741 out.get(0).set(CellTypeState.makeLineRef(bci)); | |
1742 } | |
1743 | |
1744 if (Assert.ASSERTS_ENABLED) { | |
1745 Assert.that(res_length<=4, "max value should be vv"); | |
1746 } | |
1747 | |
1748 // Compute arguments | |
1749 int arg_length = cse.computeForParameters(is_static, in); | |
1750 if (Assert.ASSERTS_ENABLED) { | |
1751 Assert.that(arg_length<=MAXARGSIZE, "too many locals"); | |
1752 } | |
1753 | |
1754 // Pop arguments | |
1755 for (int i = arg_length - 1; i >= 0; i--) ppop1(in.get(i));// Do args in reverse order. | |
1756 | |
1757 // Report results | |
1758 if (_report_result_for_send == true) { | |
1759 fillStackmapForOpcodes(_itr_send, vars(), stack(), _stack_top); | |
1760 _report_result_for_send = false; | |
1761 } | |
1762 | |
1763 // Push return address | |
1764 ppush(out); | |
1765 } | |
1766 | |
1767 void doMultianewarray (int dims, int bci) { | |
1768 if (Assert.ASSERTS_ENABLED) { | |
1769 Assert.that(dims >= 1, "sanity check"); | |
1770 } | |
1771 for(int i = dims -1; i >=0; i--) { | |
1772 ppop1(valCTS); | |
1773 } | |
1774 ppush1(CellTypeState.makeLineRef(bci)); | |
1775 } | |
1776 | |
1777 void doMonitorenter (int bci) { | |
1778 CellTypeState actual = pop(); | |
1779 if (_monitor_top == bad_monitors) { | |
1780 return; | |
1781 } | |
1782 | |
1783 // Bail out when we get repeated locks on an identical monitor. This case | |
1784 // isn't too hard to handle and can be made to work if supporting nested | |
1785 // redundant synchronized statements becomes a priority. | |
1786 // | |
1787 // See also "Note" in do_monitorexit(), below. | |
1788 if (actual.isLockReference()) { | |
1789 _monitor_top = bad_monitors; | |
1790 _monitor_safe = false; | |
1791 | |
1792 if (TraceMonitorMismatch) { | |
1793 reportMonitorMismatch("nested redundant lock -- bailout..."); | |
1794 } | |
1795 return; | |
1796 } | |
1797 | |
1798 CellTypeState lock = CellTypeState.makeLockRef(bci); | |
1799 checkType(refCTS, actual); | |
1800 if (!actual.isInfoTop()) { | |
1801 replaceAllCTSMatches(actual, lock); | |
1802 monitorPush(lock); | |
1803 } | |
1804 } | |
1805 | |
1806 void doMonitorexit (int bci) { | |
1807 CellTypeState actual = pop(); | |
1808 if (_monitor_top == bad_monitors) { | |
1809 return; | |
1810 } | |
1811 checkType(refCTS, actual); | |
1812 CellTypeState expected = monitorPop(); | |
1813 if (!actual.isLockReference() || !expected.equal(actual)) { | |
1814 // The monitor we are exiting is not verifiably the one | |
1815 // on the top of our monitor stack. This causes a monitor | |
1816 // mismatch. | |
1817 _monitor_top = bad_monitors; | |
1818 _monitor_safe = false; | |
1819 | |
1820 // We need to mark this basic block as changed so that | |
1821 // this monitorexit will be visited again. We need to | |
1822 // do this to ensure that we have accounted for the | |
1823 // possibility that this bytecode will throw an | |
1824 // exception. | |
1825 BasicBlock bb = getBasicBlockContaining(bci); | |
1826 bb.setChanged(true); | |
1827 bb._monitor_top = bad_monitors; | |
1828 | |
1829 if (TraceMonitorMismatch) { | |
1830 reportMonitorMismatch("improper monitor pair"); | |
1831 } | |
1832 } else { | |
1833 // This code is a fix for the case where we have repeated | |
1834 // locking of the same object in straightline code. We clear | |
1835 // out the lock when it is popped from the monitor stack | |
1836 // and replace it with an unobtrusive reference value that can | |
1837 // be locked again. | |
1838 // | |
1839 // Note: when generateOopMap is fixed to properly handle repeated, | |
1840 // nested, redundant locks on the same object, then this | |
1841 // fix will need to be removed at that time. | |
1842 replaceAllCTSMatches(actual, CellTypeState.makeLineRef(bci)); | |
1843 } | |
1844 | |
1845 if (_report_for_exit_bci == bci) { | |
1846 _matching_enter_bci = expected.getMonitorSource(); | |
1847 } | |
1848 } | |
1849 | |
1850 void doReturnMonitorCheck () { | |
1851 if (_monitor_top > 0) { | |
1852 // The monitor stack must be empty when we leave the method | |
1853 // for the monitors to be properly matched. | |
1854 _monitor_safe = false; | |
1855 | |
1856 // Since there are no successors to the *return bytecode, it | |
1857 // isn't necessary to set _monitor_top to bad_monitors. | |
1858 | |
1859 if (TraceMonitorMismatch) { | |
1860 reportMonitorMismatch("non-empty monitor stack at return"); | |
1861 } | |
1862 } | |
1863 } | |
1864 | |
1865 void doCheckcast () { | |
1866 CellTypeState actual = pop(); | |
1867 checkType(refCTS, actual); | |
1868 push(actual); | |
1869 } | |
1870 | |
1871 CellTypeState[] sigcharToEffect (char sigch, int bci, CellTypeState[] out) { | |
1872 // Object and array | |
1873 if (sigch=='L' || sigch=='[') { | |
1874 out[0] = CellTypeState.makeLineRef(bci); | |
1875 out[1] = CellTypeState.bottom; | |
1876 return out; | |
1877 } | |
1878 if (sigch == 'J' || sigch == 'D' ) return vvCTS; // Long and Double | |
1879 if (sigch == 'V' ) return epsilonCTS; // Void | |
1880 return vCTS; // Otherwise | |
1881 } | |
1882 | |
1883 // Copies (optionally bottom/zero terminated) CTS string from "src" into "dst". | |
1884 // Does NOT terminate with a bottom. Returns the number of cells copied. | |
1885 int copyCTS (CellTypeState[] dst, CellTypeState[] src) { | |
1886 int idx = 0; | |
1887 for (; idx < src.length && !src[idx].isBottom(); idx++) { | |
1888 dst[idx] = src[idx]; | |
1889 } | |
1890 return idx; | |
1891 } | |
1892 | |
1893 // Create result set | |
1894 boolean _report_result; | |
1895 boolean _report_result_for_send; // Unfortunatly, stackmaps for sends are special, so we need some extra | |
1896 BytecodeStream _itr_send; // variables to handle them properly. | |
1897 | |
1898 void reportResult () { | |
1899 // if (TraceNewOopMapGeneration) tty.print_cr("Report result pass"); | |
1900 | |
1901 // We now want to report the result of the parse | |
1902 _report_result = true; | |
1903 | |
1904 // Prolog code | |
1905 fillStackmapProlog(_gc_points); | |
1906 | |
1907 // Mark everything changed, then do one interpretation pass. | |
1908 for (int i = 0; i<_bb_count; i++) { | |
1909 if (_basic_blocks[i].isReachable()) { | |
1910 _basic_blocks[i].setChanged(true); | |
1911 interpBB(_basic_blocks[i]); | |
1912 } | |
1913 } | |
1914 | |
1915 // Note: Since we are skipping dead-code when we are reporting results, then | |
1916 // the no. of encountered gc-points might be fewer than the previously number | |
1917 // we have counted. (dead-code is a pain - it should be removed before we get here) | |
1918 fillStackmapEpilog(); | |
1919 | |
1920 // Report initvars | |
1921 fillInitVars(_init_vars); | |
1922 | |
1923 _report_result = false; | |
1924 } | |
1925 | |
1926 // Initvars | |
1927 List/*<Integer>*/ _init_vars; | |
1928 | |
1929 void initializeVars () { | |
1930 for (int k = 0; k < _init_vars.size(); k++) | |
1931 _state.get(((Integer) _init_vars.get(k)).intValue()).set(CellTypeState.makeSlotRef(k)); | |
1932 } | |
1933 | |
1934 void addToRefInitSet (int localNo) { | |
1935 // if (TraceNewOopMapGeneration) | |
1936 // tty.print_cr("Added init vars: %d", localNo); | |
1937 | |
1938 Integer local = new Integer(localNo); | |
1939 | |
1940 // Is it already in the set? | |
1941 if (_init_vars.contains(local)) | |
1942 return; | |
1943 | |
1944 _init_vars.add(local); | |
1945 } | |
1946 | |
1947 // Conflicts rewrite logic | |
1948 boolean _conflict; // True, if a conflict occured during interpretation | |
1949 int _nof_refval_conflicts; // No. of conflicts that require rewrites | |
1950 int[] _new_var_map; | |
1951 | |
1952 void recordRefvalConflict (int varNo) { | |
1953 if (Assert.ASSERTS_ENABLED) { | |
1954 Assert.that(varNo>=0 && varNo< _max_locals, "index out of range"); | |
1955 } | |
1956 | |
1957 if (TraceOopMapRewrites) { | |
1958 System.err.println("### Conflict detected (local no: " + varNo + ")"); | |
1959 } | |
1960 | |
1961 if (_new_var_map == null) { | |
1962 _new_var_map = new int[_max_locals]; | |
1963 for (int k = 0; k < _max_locals; k++) _new_var_map[k] = k; | |
1964 } | |
1965 | |
1966 if ( _new_var_map[varNo] == varNo) { | |
1967 // Check if max. number of locals has been reached | |
1968 if (_max_locals + _nof_refval_conflicts >= MAX_LOCAL_VARS) { | |
1969 throw new RuntimeException("Rewriting exceeded local variable limit"); | |
1970 } | |
1971 _new_var_map[varNo] = _max_locals + _nof_refval_conflicts; | |
1972 _nof_refval_conflicts++; | |
1973 } | |
1974 } | |
1975 | |
1976 void rewriteRefvalConflicts () { | |
1977 if (_nof_refval_conflicts > 0) { | |
1978 if (VM.getVM().isDebugging()) { | |
1979 throw new RuntimeException("Should not reach here (method rewriting should have been done by the VM already)"); | |
1980 } else { | |
1981 throw new RuntimeException("Method rewriting not yet implemented in Java"); | |
1982 } | |
1983 } | |
1984 } | |
1985 // Rewriting-related routines are not needed here | |
1986 // void rewrite_refval_conflict (int from, int to); | |
1987 // bool rewrite_refval_conflict_inst (BytecodeStream *i, int from, int to); | |
1988 // bool rewrite_load_or_store (BytecodeStream *i, Bytecodes.Code bc, Bytecodes.Code bc0, unsigned int varNo); | |
1989 | |
1990 // bool expand_current_instr (int bci, int ilen, int newIlen, u_char inst_buffer[]); | |
1991 // bool is_astore (BytecodeStream *itr, int *index); | |
1992 // bool is_aload (BytecodeStream *itr, int *index); | |
1993 | |
1994 // List of bci's where a return address is on top of the stack | |
1995 // GrowableArray<intptr_t> *_ret_adr_tos; | |
1996 | |
1997 // bool stack_top_holds_ret_addr (int bci); | |
1998 // void compute_ret_adr_at_TOS (); | |
1999 // void update_ret_adr_at_TOS (int bci, int delta); | |
2000 | |
2001 String stateVecToString (CellTypeStateList vec, int len) { | |
2002 for (int i = 0; i < len; i++) { | |
2003 _state_vec_buf[i] = vec.get(i).toChar(); | |
2004 } | |
2005 return new String(_state_vec_buf, 0, len); | |
2006 } | |
2007 | |
2008 // Helper method. Can be used in subclasses to fx. calculate gc_points. If the current instuction | |
2009 // is a control transfer, then calls the jmpFct all possible destinations. | |
2010 void retJumpTargetsDo (BytecodeStream bcs, JumpClosure closure, int varNo, int[] data) { | |
2011 CellTypeState ra = vars().get(varNo); | |
2012 if (!ra.isGoodAddress()) { | |
2013 throw new RuntimeException("ret returns from two jsr subroutines?"); | |
2014 } | |
2015 int target = ra.getInfo(); | |
2016 | |
2017 RetTableEntry rtEnt = _rt.findJsrsForTarget(target); | |
2018 int bci = bcs.bci(); | |
2019 for (int i = 0; i < rtEnt.nofJsrs(); i++) { | |
2020 int target_bci = rtEnt.jsrs(i); | |
2021 // Make sure a jrtRet does not set the changed bit for dead basicblock. | |
2022 BasicBlock jsr_bb = getBasicBlockContaining(target_bci - 1); | |
2023 if (Assert.ASSERTS_ENABLED) { | |
2024 BasicBlock target_bb = _basic_blocks[1 + bbIndex(jsr_bb)]; | |
2025 Assert.that(target_bb == getBasicBlockAt(target_bci), "wrong calc. of successor basicblock"); | |
2026 } | |
2027 boolean alive = jsr_bb.isAlive(); | |
2028 // if (TraceNewOopMapGeneration) { | |
2029 // tty.print("pc = %d, ret . %d alive: %s\n", bci, target_bci, alive ? "true" : "false"); | |
2030 // } | |
2031 if (alive) { | |
2032 closure.process(this, target_bci, data); | |
2033 } | |
2034 } | |
2035 } | |
2036 | |
2037 /** If the current instruction in "c" has no effect on control flow, | |
2038 returns "true". Otherwise, calls "closure.process()" one or | |
2039 more times, with "c", an appropriate "pcDelta", and "data" as | |
2040 arguments, then returns "false". There is one exception: if the | |
2041 current instruction is a "ret", returns "false" without calling | |
2042 "jmpFct". Arrangements for tracking the control flow of a "ret" | |
2043 must be made externally. */ | |
2044 boolean jumpTargetsDo (BytecodeStream bcs, JumpClosure closure, int[] data) { | |
2045 int bci = bcs.bci(); | |
2046 | |
2047 switch (bcs.code()) { | |
2048 case Bytecodes._ifeq: | |
2049 case Bytecodes._ifne: | |
2050 case Bytecodes._iflt: | |
2051 case Bytecodes._ifge: | |
2052 case Bytecodes._ifgt: | |
2053 case Bytecodes._ifle: | |
2054 case Bytecodes._if_icmpeq: | |
2055 case Bytecodes._if_icmpne: | |
2056 case Bytecodes._if_icmplt: | |
2057 case Bytecodes._if_icmpge: | |
2058 case Bytecodes._if_icmpgt: | |
2059 case Bytecodes._if_icmple: | |
2060 case Bytecodes._if_acmpeq: | |
2061 case Bytecodes._if_acmpne: | |
2062 case Bytecodes._ifnull: | |
2063 case Bytecodes._ifnonnull: | |
2064 closure.process(this, bcs.dest(), data); | |
2065 closure.process(this, bci + 3, data); | |
2066 break; | |
2067 | |
2068 case Bytecodes._goto: | |
2069 closure.process(this, bcs.dest(), data); | |
2070 break; | |
2071 case Bytecodes._goto_w: | |
2072 closure.process(this, bcs.dest_w(), data); | |
2073 break; | |
2074 case Bytecodes._tableswitch: | |
2075 { | |
2076 BytecodeTableswitch tableswitch = BytecodeTableswitch.at(bcs); | |
2077 int len = tableswitch.length(); | |
2078 | |
2079 closure.process(this, bci + tableswitch.defaultOffset(), data); /* Default. jump address */ | |
2080 while (--len >= 0) { | |
2081 closure.process(this, bci + tableswitch.destOffsetAt(len), data); | |
2082 } | |
2083 break; | |
2084 } | |
2085 | |
2086 case Bytecodes._fast_linearswitch: // Java opcodes | |
2087 case Bytecodes._fast_binaryswitch: // get_int_table handles conversions | |
2088 case Bytecodes._lookupswitch: | |
2089 { | |
2090 BytecodeLookupswitch lookupswitch = BytecodeLookupswitch.at(bcs); | |
2091 int npairs = lookupswitch.numberOfPairs(); | |
2092 closure.process(this, bci + lookupswitch.defaultOffset(), data); /* Default. */ | |
2093 while(--npairs >= 0) { | |
2094 LookupswitchPair pair = lookupswitch.pairAt(npairs); | |
2095 closure.process(this, bci + pair.offset(), data); | |
2096 } | |
2097 break; | |
2098 } | |
2099 case Bytecodes._jsr: | |
2100 Assert.that(bcs.isWide()==false, "sanity check"); | |
2101 closure.process(this, bcs.dest(), data); | |
2102 break; | |
2103 case Bytecodes._jsr_w: | |
2104 closure.process(this, bcs.dest_w(), data); | |
2105 break; | |
2106 case Bytecodes._wide: | |
2107 throw new RuntimeException("Should not reach here"); | |
2108 case Bytecodes._athrow: | |
2109 case Bytecodes._ireturn: | |
2110 case Bytecodes._lreturn: | |
2111 case Bytecodes._freturn: | |
2112 case Bytecodes._dreturn: | |
2113 case Bytecodes._areturn: | |
2114 case Bytecodes._return: | |
2115 case Bytecodes._ret: | |
2116 break; | |
2117 default: | |
2118 return true; | |
2119 } | |
2120 return false; | |
2121 } | |
2122 | |
2123 // Monitor matching | |
2124 // int fill_out_arrays (int *enter, int *exit, int max); | |
2125 | |
2126 // friend class RelocCallback; | |
2127 | |
2128 //---------------------------------------------------------------------- | |
2129 // Public routines for GenerateOopMap | |
2130 // | |
2131 public GenerateOopMap(Method method) { | |
2132 // We have to initialize all variables here, that can be queried direcly | |
2133 _method = method; | |
2134 _max_locals=0; | |
2135 _init_vars = null; | |
2136 _rt = new RetTable(); | |
2137 } | |
2138 | |
2139 | |
2140 // Compute the map. | |
2141 public void computeMap() { | |
2142 if (DEBUG) { | |
2143 System.err.println("*** GenerateOopMap: computing for " + | |
2144 method().getMethodHolder().getName().asString() + "." + | |
2145 method().getName().asString() + | |
2146 method().getSignature().asString()); | |
2147 } | |
2148 | |
2149 // Initialize values | |
2150 _got_error = false; | |
2151 _conflict = false; | |
2152 _max_locals = (int) method().getMaxLocals(); | |
2153 _max_stack = (int) method().getMaxStack(); | |
2154 _has_exceptions = (method().getExceptionTable().getLength() > 0); | |
2155 _nof_refval_conflicts = 0; | |
2156 _init_vars = new ArrayList(5); // There are seldom more than 5 init_vars | |
2157 _report_result = false; | |
2158 _report_result_for_send = false; | |
2159 _report_for_exit_bci = -1; | |
2160 _new_var_map = null; | |
2161 // _ret_adr_tos = new GrowableArray<intptr_t>(5); // 5 seems like a good number; | |
2162 // _did_rewriting = false; | |
2163 // _did_relocation = false; | |
2164 | |
2165 // FIXME: remove | |
2166 /* | |
2167 if (TraceNewOopMapGeneration) { | |
2168 tty.print("Method name: %s\n", method().name().as_C_string()); | |
2169 if (Verbose) { | |
2170 _method.print_codes(); | |
2171 tty.print_cr("Exception table:"); | |
2172 typeArrayOop excps = method().exception_table(); | |
2173 for(int i = 0; i < excps.length(); i += 4) { | |
2174 tty.print_cr("[%d - %d] . %d", excps.int_at(i + 0), excps.int_at(i + 1), excps.int_at(i + 2)); | |
2175 } | |
2176 } | |
2177 } | |
2178 */ | |
2179 | |
2180 // if no code - do nothing | |
2181 // compiler needs info | |
2182 if (method().getCodeSize() == 0 || _max_locals + method().getMaxStack() == 0) { | |
2183 fillStackmapProlog(0); | |
2184 fillStackmapEpilog(); | |
2185 return; | |
2186 } | |
2187 // Step 1: Compute all jump targets and their return value | |
2188 if (!_got_error) | |
2189 _rt.computeRetTable(_method); | |
2190 | |
2191 // Step 2: Find all basic blocks and count GC points | |
2192 if (!_got_error) | |
2193 markBBHeadersAndCountGCPoints(); | |
2194 | |
2195 // Step 3: Calculate stack maps | |
2196 if (!_got_error) | |
2197 doInterpretation(); | |
2198 | |
2199 // Step 4:Return results | |
2200 if (!_got_error && reportResults()) | |
2201 reportResult(); | |
2202 | |
2203 if (_got_error) { | |
2204 // We could expand this code to throw somekind of exception (e.g., VerifyException). However, | |
2205 // an exception thrown in this part of the code is likly to mean that we are executing some | |
2206 // illegal bytecodes (that the verifier should have caught if turned on), so we will just exit | |
2207 // with a fatal. | |
2208 throw new RuntimeException("Illegal bytecode sequence encountered while generating interpreter pointer maps - method should be rejected by verifier."); | |
2209 } | |
2210 } | |
2211 | |
2212 // Do a callback on fill_stackmap_for_opcodes for basicblock containing bci | |
2213 public void resultForBasicblock(int bci) { | |
2214 // FIXME: remove | |
2215 // if (TraceNewOopMapGeneration) tty.print_cr("Report result pass for basicblock"); | |
2216 | |
2217 // We now want to report the result of the parse | |
2218 _report_result = true; | |
2219 | |
2220 // Find basicblock and report results | |
2221 BasicBlock bb = getBasicBlockContaining(bci); | |
2222 if (Assert.ASSERTS_ENABLED) { | |
2223 Assert.that(bb.isReachable(), "getting result from unreachable basicblock"); | |
2224 } | |
2225 bb.setChanged(true); | |
2226 interpBB(bb); | |
2227 } | |
2228 | |
2229 // Query | |
2230 public int maxLocals() { return _max_locals; } | |
2231 public Method method() { return _method; } | |
2232 | |
2233 // bool did_rewriting() { return _did_rewriting; } | |
2234 // bool did_relocation() { return _did_relocation; } | |
2235 | |
2236 // static void print_time(); | |
2237 | |
2238 // Monitor query | |
2239 public boolean monitorSafe() { return _monitor_safe; } | |
2240 // Takes as input the bci of a monitorexit bytecode. | |
2241 // Returns the bci of the corresponding monitorenter. | |
2242 // Can only be called safely after computeMap() is run. | |
2243 public int getMonitorMatch(int bci) { | |
2244 if (Assert.ASSERTS_ENABLED) { | |
2245 Assert.that(_monitor_safe, "Attempt to match monitor in broken code."); | |
2246 } | |
2247 | |
2248 // if (TraceNewOopMapGeneration) | |
2249 // tty.print_cr("Report monitor match for bci : %d", bci); | |
2250 | |
2251 // We want to report the line number of the monitorenter. | |
2252 _report_for_exit_bci = bci; | |
2253 _matching_enter_bci = -1; | |
2254 | |
2255 // Find basicblock and report results | |
2256 BasicBlock bb = getBasicBlockContaining(bci); | |
2257 if (bb.isReachable()) { | |
2258 bb.setChanged(true); | |
2259 interpBB(bb); | |
2260 _report_for_exit_bci = -1; | |
2261 if (Assert.ASSERTS_ENABLED) { | |
2262 Assert.that(_matching_enter_bci != -1, "monitor matching invariant"); | |
2263 } | |
2264 } | |
2265 return _matching_enter_bci; | |
2266 } | |
2267 | |
2268 // Returns a Arena allocated object that contains pairing info. | |
2269 // MonitorPairs* get_pairing(Arena *arena); | |
2270 | |
2271 // copies monitor pairing info into area; area_count specifies maximum | |
2272 // possible number of monitor pairs | |
2273 // int copy_pairing(int pair_count, MonitorPairs* pairs); | |
2274 | |
2275 private int bbIndex(BasicBlock bb) { | |
2276 for (int i = 0; i < _basic_blocks.length; i++) { | |
2277 if (_basic_blocks[i] == bb) { | |
2278 return i; | |
2279 } | |
2280 } | |
2281 throw new RuntimeException("Should have found block"); | |
2282 } | |
2283 | |
2284 //---------------------------------------------------------------------- | |
2285 // Specialization methods. Intended use: | |
2286 // - possibleGCPoint must return true for every bci for which the | |
2287 // stackmaps must be returned | |
2288 // - fillStackmapProlog is called just before the result is | |
2289 // reported. The arguments tells the estimated number of gc points | |
2290 // - fillStackmapForOpcodes is called once for each bytecode index | |
2291 // in order (0...code_length-1) | |
2292 // - fillStackmapEpilog is called after all results has been | |
2293 // reported. Note: Since the algorithm does not report stackmaps for | |
2294 // deadcode, fewer gc_points might have been encounted than assumed | |
2295 // during the epilog. It is the responsibility of the subclass to | |
2296 // count the correct number. | |
2297 // - fillInitVars are called once with the result of the init_vars | |
2298 // computation | |
2299 // | |
2300 // All these methods are used during a call to computeMap. Note: | |
2301 // None of the return results are valid after computeMap returns, | |
2302 // since all values are allocated as resource objects. | |
2303 // | |
2304 // All virtual method must be implemented in subclasses | |
2305 public boolean allowRewrites () { return false; } | |
2306 public boolean reportResults () { return true; } | |
2307 public boolean reportInitVars () { return true; } | |
2308 public boolean possibleGCPoint (BytecodeStream bcs) { throw new RuntimeException("ShouldNotReachHere"); } | |
2309 public void fillStackmapProlog (int nofGCPoints) { throw new RuntimeException("ShouldNotReachHere"); } | |
2310 public void fillStackmapEpilog () { throw new RuntimeException("ShouldNotReachHere"); } | |
2311 public void fillStackmapForOpcodes (BytecodeStream bcs, | |
2312 CellTypeStateList vars, | |
2313 CellTypeStateList stack, | |
2314 int stackTop) { throw new RuntimeException("ShouldNotReachHere"); } | |
2315 public void fillInitVars (List/*<Integer>*/ init_vars) { throw new RuntimeException("ShouldNotReachHere"); } | |
2316 } |