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