0
|
1 /*
|
|
2 * Copyright 2000-2006 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.runtime;
|
|
26
|
|
27 import java.util.*;
|
|
28 import sun.jvm.hotspot.code.*;
|
|
29 import sun.jvm.hotspot.debugger.*;
|
|
30 import sun.jvm.hotspot.oops.*;
|
|
31 import sun.jvm.hotspot.utilities.*;
|
|
32
|
|
33 /** FIXME: missing many accessors; all we have right now is the method
|
|
34 and BCI. NOTE that this has been modified from the VM's version to
|
|
35 handle NULL ScopeDescs for the debugging case. This simplifies
|
|
36 using code a great deal. */
|
|
37
|
|
38 public class CompiledVFrame extends JavaVFrame {
|
|
39 private ScopeDesc scope;
|
|
40 private boolean mayBeImprecise;
|
|
41
|
|
42 public CompiledVFrame(Frame fr, RegisterMap regMap, JavaThread thread, ScopeDesc scope, boolean mayBeImprecise) {
|
|
43 super(fr, regMap, thread);
|
|
44 this.scope = scope;
|
|
45 this.mayBeImprecise = mayBeImprecise;
|
|
46 if (!VM.getVM().isDebugging()) {
|
|
47 Assert.that(scope != null, "scope must be present");
|
|
48 }
|
|
49 }
|
|
50
|
|
51 public boolean isTop() {
|
|
52 if (VM.getVM().isDebugging()) {
|
|
53 return (getScope() == null || getScope().isTop());
|
|
54 } else {
|
|
55 return getScope().isTop();
|
|
56 }
|
|
57 }
|
|
58
|
|
59 public boolean isCompiledFrame() {
|
|
60 return true;
|
|
61 }
|
|
62
|
|
63 public boolean isDeoptimized() {
|
|
64 return fr.isDeoptimized();
|
|
65 }
|
|
66
|
|
67 public boolean mayBeImpreciseDbg() {
|
|
68 return mayBeImprecise;
|
|
69 }
|
|
70
|
|
71 /** Returns the active method */
|
|
72 public NMethod getCode() {
|
|
73 return VM.getVM().getCodeCache().findNMethod(fr.getPC());
|
|
74 }
|
|
75
|
|
76 /** Returns the active method. Does not perform a guarantee
|
|
77 regarding unloaded methods -- more suitable for debugging
|
|
78 system. */
|
|
79 public NMethod getCodeUnsafe() {
|
|
80 return VM.getVM().getCodeCache().findNMethodUnsafe(fr.getPC());
|
|
81 }
|
|
82
|
|
83 /** Returns the ScopeDesc */
|
|
84 public ScopeDesc getScope() {
|
|
85 return scope;
|
|
86 }
|
|
87
|
|
88 public Method getMethod() {
|
|
89 if (VM.getVM().isDebugging() && getScope() == null) {
|
|
90 return getCodeUnsafe().getMethod();
|
|
91 }
|
|
92 return getScope().getMethod();
|
|
93 }
|
|
94
|
|
95 public StackValueCollection getLocals() {
|
|
96 List scvList = getScope().getLocals();
|
|
97 if (scvList == null)
|
|
98 return new StackValueCollection();
|
|
99
|
|
100 // scvList is the list of ScopeValues describing the JVM stack state.
|
|
101 // There is one scv_list entry for every JVM stack state in use.
|
|
102 int length = scvList.size();
|
|
103 StackValueCollection result = new StackValueCollection(length);
|
|
104 for( int i = 0; i < length; i++ )
|
|
105 result.add( createStackValue((ScopeValue) scvList.get(i)) );
|
|
106
|
|
107 return result;
|
|
108 }
|
|
109
|
|
110 public StackValueCollection getExpressions() {
|
|
111 List scvList = getScope().getExpressions();
|
|
112 if (scvList == null)
|
|
113 return new StackValueCollection();
|
|
114
|
|
115 // scvList is the list of ScopeValues describing the JVM stack state.
|
|
116 // There is one scv_list entry for every JVM stack state in use.
|
|
117 int length = scvList.size();
|
|
118 StackValueCollection result = new StackValueCollection(length);
|
|
119 for( int i = 0; i < length; i++ )
|
|
120 result.add( createStackValue((ScopeValue) scvList.get(i)) );
|
|
121
|
|
122 return result;
|
|
123 }
|
|
124
|
|
125 /** Returns List<MonitorInfo> */
|
|
126 public List getMonitors() {
|
|
127 List monitors = getScope().getMonitors();
|
|
128 if (monitors == null) {
|
|
129 return new ArrayList();
|
|
130 }
|
|
131 List result = new ArrayList(monitors.size());
|
|
132 for (int i = 0; i < monitors.size(); i++) {
|
|
133 MonitorValue mv = (MonitorValue) monitors.get(i);
|
|
134 StackValue ownerSV = createStackValue(mv.owner()); // it is an oop
|
|
135 result.add(new MonitorInfo(ownerSV.getObject(), resolveMonitorLock(mv.basicLock())));
|
|
136 }
|
|
137 return result;
|
|
138 }
|
|
139
|
|
140 public int getBCI() {
|
|
141 int raw = getRawBCI();
|
|
142 return ((raw == DebugInformationRecorder.SYNCHRONIZATION_ENTRY_BCI) ? 0 : raw);
|
|
143 }
|
|
144
|
|
145 /** Returns SynchronizationEntryBCI or bci() (used for synchronization) */
|
|
146 public int getRawBCI() {
|
|
147 if (VM.getVM().isDebugging() && getScope() == null) {
|
|
148 return 0; // No debugging information!
|
|
149 }
|
|
150 return getScope().getBCI();
|
|
151 }
|
|
152
|
|
153 /** Returns the sender vframe */
|
|
154 public VFrame sender() {
|
|
155 if (Assert.ASSERTS_ENABLED) {
|
|
156 Assert.that(isTop(), "just checking");
|
|
157 }
|
|
158 return sender(false);
|
|
159 }
|
|
160
|
|
161 public VFrame sender(boolean mayBeImprecise) {
|
|
162 if (!VM.getVM().isDebugging()) {
|
|
163 if (Assert.ASSERTS_ENABLED) {
|
|
164 Assert.that(scope != null, "When new stub generator is in place, then scope can never be NULL");
|
|
165 }
|
|
166 }
|
|
167 Frame f = (Frame) getFrame().clone();
|
|
168 return (isTop()
|
|
169 ? super.sender(false)
|
|
170 : new CompiledVFrame(f, getRegisterMap(), getThread(), getScope().sender(), mayBeImprecise));
|
|
171 }
|
|
172
|
|
173 private StackValue createStackValue(ScopeValue sv) {
|
|
174 // FIXME: this code appears to be out-of-date with respect to the VM especially in 64-bit mode
|
|
175 if (sv.isLocation()) {
|
|
176 // Stack or register value
|
|
177 Location loc = ((LocationValue) sv).getLocation();
|
|
178
|
|
179 if (loc.isIllegal()) return new StackValue();
|
|
180
|
|
181 // First find address of value
|
|
182 Address valueAddr = loc.isRegister()
|
|
183 // Value was in a callee-save register
|
|
184 ? getRegisterMap().getLocation(new VMReg(loc.getRegisterNumber()))
|
|
185 // Else value was directly saved on the stack. The frame's original stack pointer,
|
|
186 // before any extension by its callee (due to Compiler1 linkage on SPARC), must be used.
|
|
187 : ((Address)fr.getUnextendedSP()).addOffsetTo(loc.getStackOffset());
|
|
188
|
|
189 // Then package it right depending on type
|
|
190 if (loc.holdsFloat()) { // Holds a float in a double register?
|
|
191 // The callee has no clue whether the register holds a float,
|
|
192 // double or is unused. He always saves a double. Here we know
|
|
193 // a double was saved, but we only want a float back. Narrow the
|
|
194 // saved double to the float that the JVM wants.
|
|
195 if (Assert.ASSERTS_ENABLED) {
|
|
196 Assert.that( loc.isRegister(), "floats always saved to stack in 1 word" );
|
|
197 }
|
|
198 float value = (float) valueAddr.getJDoubleAt(0);
|
|
199 return new StackValue(Float.floatToIntBits(value) & 0xFFFFFFFF); // 64-bit high half is stack junk
|
|
200 } else if (loc.holdsInt()) { // Holds an int in a long register?
|
|
201 // The callee has no clue whether the register holds an int,
|
|
202 // long or is unused. He always saves a long. Here we know
|
|
203 // a long was saved, but we only want an int back. Narrow the
|
|
204 // saved long to the int that the JVM wants.
|
|
205 if (Assert.ASSERTS_ENABLED) {
|
|
206 Assert.that( loc.isRegister(), "ints always saved to stack in 1 word" );
|
|
207 }
|
|
208 return new StackValue(valueAddr.getJLongAt(0) & 0xFFFFFFFF);
|
331
|
209 } else if (loc.holdsNarrowOop()) { // Holds an narrow oop?
|
|
210 if (loc.isRegister() && VM.getVM().isBigEndian()) {
|
|
211 // The callee has no clue whether the register holds an narrow oop,
|
|
212 // long or is unused. He always saves a long. Here we know
|
|
213 // a long was saved, but we only want an narrow oop back. Narrow the
|
|
214 // saved long to the narrow oop that the JVM wants.
|
|
215 return new StackValue(valueAddr.getCompOopHandleAt(VM.getVM().getIntSize()));
|
|
216 } else {
|
|
217 return new StackValue(valueAddr.getCompOopHandleAt(0));
|
|
218 }
|
0
|
219 } else if( loc.holdsOop() ) { // Holds an oop?
|
|
220 return new StackValue(valueAddr.getOopHandleAt(0));
|
|
221 } else if( loc.holdsDouble() ) {
|
|
222 // Double value in a single stack slot
|
|
223 return new StackValue(valueAddr.getJIntAt(0) & 0xFFFFFFFF);
|
|
224 } else if(loc.holdsAddr()) {
|
|
225 if (Assert.ASSERTS_ENABLED) {
|
|
226 Assert.that(!VM.getVM().isServerCompiler(), "No address type for locations with C2 (jsr-s are inlined)");
|
|
227 }
|
|
228 // FIXME: not yet implemented (no access to safepoint state yet)
|
|
229 return new StackValue(0);
|
|
230 // intptr_t return_addr_tmp = *(intptr_t *)value_addr;
|
|
231 // int bci = -1;
|
|
232 // // Get the bci of the jsr that generated this returnAddress value.
|
|
233 // // If the destination of a jsr is a block that ends with a return or throw, then
|
|
234 // // the GraphBuilder converts the jsr into a direct goto. This has the side effect that
|
|
235 // // the return address for the jsr gets emitted as a bci instead of as a real pc
|
|
236 // if (code()->contains((address)return_addr_tmp)) {
|
|
237 // ScopeDesc* scope = code()->scope_desc_at((address)(return_addr_tmp - jsr_call_offset), false);
|
|
238 // bci = scope->bci();
|
|
239 // } else {
|
|
240 // bci = (int)return_addr_tmp;
|
|
241 // }
|
|
242 // // no need to lock method as this happens at Safepoint
|
|
243 // assert (SafepointSynchronize::is_at_safepoint(), "must be at safepoint, otherwise lock method()");
|
|
244 // // make sure bci points to jsr
|
|
245 // Bytecode* bytecode = Bytecode_at(method()->bcp_from(bci));
|
|
246 // Bytecodes::Code bc = bytecode->code();
|
|
247 // assert (bc == Bytecodes::_jsr || bc == Bytecodes::_jsr_w, "must be jsr");
|
|
248 //
|
|
249 // // the real returnAddress is the bytecode following the jsr
|
|
250 // return new StackValue((intptr_t)(bci + Bytecodes::length_for(bc)));
|
|
251 } else if (VM.getVM().isLP64() && loc.holdsLong()) {
|
|
252 if ( loc.isRegister() ) {
|
|
253 // Long value in two registers, high half in the first, low in the second
|
|
254 return new StackValue(((valueAddr.getJLongAt(0) & 0xFFFFFFFF) << 32) |
|
|
255 ((valueAddr.getJLongAt(8) & 0xFFFFFFFF)));
|
|
256 } else {
|
|
257 // Long value in a single stack slot
|
|
258 return new StackValue(valueAddr.getJLongAt(0));
|
|
259 }
|
|
260 } else if( loc.isRegister() ) {
|
|
261 // At the moment, all non-oop values in registers are 4 bytes,
|
|
262 // including double and long halves (see Compile::FillLocArray() in
|
|
263 // opto/output.cpp). Haul them out as such and return a StackValue
|
|
264 // containing an image of the value as it appears in a stack slot.
|
|
265 // If this is a double or long half, the interpreter _must_ deal
|
|
266 // with doubles and longs as entities split across two stack slots.
|
|
267 // To change this so doubles and/or longs can live in one stack slot,
|
|
268 // a StackValue will have to understand that it can contain an
|
|
269 // undivided double or long, implying that a Location (and the debug
|
|
270 // info mechanism) and FillLocArray() will also have to understand it.
|
|
271 return new StackValue(valueAddr.getJIntAt(0) & 0xFFFFFFFF);
|
|
272 } else {
|
|
273 return new StackValue(valueAddr.getJIntAt(0) & 0xFFFFFFFF);
|
|
274 }
|
|
275 } else if (sv.isConstantInt()) {
|
|
276 // Constant int: treat same as register int.
|
|
277 return new StackValue(((ConstantIntValue) sv).getValue() & 0xFFFFFFFF);
|
|
278 } else if (sv.isConstantOop()) {
|
|
279 // constant oop
|
|
280 return new StackValue(((ConstantOopReadValue) sv).getValue());
|
|
281 } else if (sv.isConstantDouble()) {
|
|
282 // Constant double in a single stack slot
|
|
283 double d = ((ConstantDoubleValue) sv).getValue();
|
|
284 return new StackValue(Double.doubleToLongBits(d) & 0xFFFFFFFF);
|
|
285 } else if (VM.getVM().isLP64() && sv.isConstantLong()) {
|
|
286 // Constant long in a single stack slot
|
|
287 return new StackValue(((ConstantLongValue) sv).getValue() & 0xFFFFFFFF);
|
|
288 }
|
|
289
|
|
290 // Unknown ScopeValue type
|
|
291 Assert.that(false, "Should not reach here");
|
|
292 return new StackValue(0); // dummy
|
|
293 }
|
|
294
|
|
295 private BasicLock resolveMonitorLock(Location location) {
|
|
296 if (Assert.ASSERTS_ENABLED) {
|
|
297 Assert.that(location.isStack(), "for now we only look at the stack");
|
|
298 }
|
|
299 int byteOffset = location.getStackOffset();
|
|
300 // (stack picture)
|
|
301 // high: [ ] byte_offset + wordSize
|
|
302 // low [ ] byte_offset
|
|
303 //
|
|
304 // sp-> [ ] 0
|
|
305 // the byte_offset is the distance from the stack pointer to the lowest address
|
|
306 // The frame's original stack pointer, before any extension by its callee
|
|
307 // (due to Compiler1 linkage on SPARC), must be used.
|
|
308 return new BasicLock(getFrame().getUnextendedSP().addOffsetTo(byteOffset));
|
|
309 }
|
|
310 }
|