1 /* 2 * Copyright (c) 2000, 2017, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * 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 if (getScope() == null) 97 return new StackValueCollection(); 98 List scvList = getScope().getLocals(); 99 if (scvList == null) 100 return new StackValueCollection(); 101 102 // scvList is the list of ScopeValues describing the JVM stack state. 103 // There is one scv_list entry for every JVM stack state in use. 104 int length = scvList.size(); 105 StackValueCollection result = new StackValueCollection(length); 106 for( int i = 0; i < length; i++ ) 107 result.add( createStackValue((ScopeValue) scvList.get(i)) ); 108 109 return result; 110 } 111 112 public StackValueCollection getExpressions() { 113 if (getScope() == null) 114 return new StackValueCollection(); 115 List scvList = getScope().getExpressions(); 116 if (scvList == null) 117 return new StackValueCollection(); 118 119 // scvList is the list of ScopeValues describing the JVM stack state. 120 // There is one scv_list entry for every JVM stack state in use. 121 int length = scvList.size(); 122 StackValueCollection result = new StackValueCollection(length); 123 for( int i = 0; i < length; i++ ) 124 result.add( createStackValue((ScopeValue) scvList.get(i)) ); 125 126 return result; 127 } 128 129 /** Returns List<MonitorInfo> */ 130 public List<MonitorInfo> getMonitors() { 131 if (getScope() == null) { 132 return new ArrayList<>(); 133 } 134 List monitors = getScope().getMonitors(); 135 if (monitors == null) { 136 return new ArrayList<>(); 137 } 138 List<MonitorInfo> result = new ArrayList<>(monitors.size()); 139 for (int i = 0; i < monitors.size(); i++) { 140 MonitorValue mv = (MonitorValue) monitors.get(i); 141 ScopeValue ov = mv.owner(); 142 StackValue ownerSV = createStackValue(ov); // it is an oop 143 if (ov.isObject()) { // The owner object was scalar replaced 144 Assert.that(mv.eliminated() && ownerSV.objIsScalarReplaced(), "monitor should be eliminated for scalar replaced object"); 145 // Put klass for scalar replaced object. 146 ScopeValue kv = ((ObjectValue)ov).getKlass(); 147 Assert.that(kv.isConstantOop(), "klass should be oop constant for scalar replaced object"); 148 OopHandle k = ((ConstantOopReadValue)kv).getValue(); 149 result.add(new MonitorInfo(k, resolveMonitorLock(mv.basicLock()), mv.eliminated(), true)); 150 } else { 151 result.add(new MonitorInfo(ownerSV.getObject(), resolveMonitorLock(mv.basicLock()), mv.eliminated(), false)); 152 } 153 } 154 return result; 155 } 156 157 public int getBCI() { 158 int raw = getRawBCI(); 159 return ((raw == DebugInformationRecorder.SYNCHRONIZATION_ENTRY_BCI) ? 0 : raw); 160 } 161 162 /** Returns SynchronizationEntryBCI or bci() (used for synchronization) */ 163 public int getRawBCI() { 164 if (VM.getVM().isDebugging() && getScope() == null) { 165 return 0; // No debugging information! 166 } 167 return getScope().getBCI(); 168 } 169 170 /** Returns the sender vframe */ 171 public VFrame sender() { 172 if (Assert.ASSERTS_ENABLED) { 173 Assert.that(isTop(), "just checking"); 174 } 175 return sender(false); 176 } 177 178 public VFrame sender(boolean mayBeImprecise) { 179 if (!VM.getVM().isDebugging()) { 180 if (Assert.ASSERTS_ENABLED) { 181 Assert.that(scope != null, "When new stub generator is in place, then scope can never be NULL"); 182 } 183 } 184 Frame f = (Frame) getFrame().clone(); 185 return (isTop() 186 ? super.sender(false) 187 : new CompiledVFrame(f, getRegisterMap(), getThread(), getScope().sender(), mayBeImprecise)); 188 } 189 190 private StackValue createStackValue(ScopeValue sv) { 191 // FIXME: this code appears to be out-of-date with respect to the VM especially in 64-bit mode 192 if (sv.isLocation()) { 193 // Stack or register value 194 Location loc = ((LocationValue) sv).getLocation(); 195 196 if (loc.isIllegal()) return new StackValue(); 197 198 // First find address of value 199 Address valueAddr = loc.isRegister() 200 // Value was in a callee-save register 201 ? getRegisterMap().getLocation(new VMReg(loc.getRegisterNumber())) 202 // Else value was directly saved on the stack. The frame's original stack pointer, 203 // before any extension by its callee (due to Compiler1 linkage on SPARC), must be used. 204 : ((Address)fr.getUnextendedSP()).addOffsetTo(loc.getStackOffset()); 205 206 // Then package it right depending on type 207 if (loc.holdsFloat()) { // Holds a float in a double register? 208 // The callee has no clue whether the register holds a float, 209 // double or is unused. He always saves a double. Here we know 210 // a double was saved, but we only want a float back. Narrow the 211 // saved double to the float that the JVM wants. 212 if (Assert.ASSERTS_ENABLED) { 213 Assert.that( loc.isRegister(), "floats always saved to stack in 1 word" ); 214 } 215 float value = (float) valueAddr.getJDoubleAt(0); 216 return new StackValue(Float.floatToIntBits(value) & 0xFFFFFFFF); // 64-bit high half is stack junk 217 } else if (loc.holdsInt()) { // Holds an int in a long register? 218 // The callee has no clue whether the register holds an int, 219 // long or is unused. He always saves a long. Here we know 220 // a long was saved, but we only want an int back. Narrow the 221 // saved long to the int that the JVM wants. 222 if (Assert.ASSERTS_ENABLED) { 223 Assert.that( loc.isRegister(), "ints always saved to stack in 1 word" ); 224 } 225 return new StackValue(valueAddr.getJLongAt(0) & 0xFFFFFFFF); 226 } else if (loc.holdsNarrowOop()) { // Holds an narrow oop? 227 if (loc.isRegister() && VM.getVM().isBigEndian()) { 228 // The callee has no clue whether the register holds an narrow oop, 229 // long or is unused. He always saves a long. Here we know 230 // a long was saved, but we only want an narrow oop back. Narrow the 231 // saved long to the narrow oop that the JVM wants. 232 return new StackValue(valueAddr.getCompOopHandleAt(VM.getVM().getIntSize()), 0); 233 } else { 234 return new StackValue(valueAddr.getCompOopHandleAt(0), 0); 235 } 236 } else if( loc.holdsOop() ) { // Holds an oop? 237 return new StackValue(valueAddr.getOopHandleAt(0), 0); 238 } else if( loc.holdsDouble() ) { 239 // Double value in a single stack slot 240 return new StackValue(valueAddr.getJIntAt(0) & 0xFFFFFFFF); 241 } else if(loc.holdsAddr()) { 242 if (Assert.ASSERTS_ENABLED) { 243 Assert.that(!VM.getVM().isServerCompiler(), "No address type for locations with C2 (jsr-s are inlined)"); 244 } 245 // FIXME: not yet implemented (no access to safepoint state yet) 246 return new StackValue(0); 247 // intptr_t return_addr_tmp = *(intptr_t *)value_addr; 248 // int bci = -1; 249 // // Get the bci of the jsr that generated this returnAddress value. 250 // // If the destination of a jsr is a block that ends with a return or throw, then 251 // // the GraphBuilder converts the jsr into a direct goto. This has the side effect that 252 // // the return address for the jsr gets emitted as a bci instead of as a real pc 253 // if (code()->contains((address)return_addr_tmp)) { 254 // ScopeDesc* scope = code()->scope_desc_at((address)(return_addr_tmp - jsr_call_offset), false); 255 // bci = scope->bci(); 256 // } else { 257 // bci = (int)return_addr_tmp; 258 // } 259 // // no need to lock method as this happens at Safepoint 260 // assert (SafepointSynchronize::is_at_safepoint(), "must be at safepoint, otherwise lock method()"); 261 // // make sure bci points to jsr 262 // Bytecode* bytecode = Bytecode_at(method()->bcp_from(bci)); 263 // Bytecodes::Code bc = bytecode->code(); 264 // assert (bc == Bytecodes::_jsr || bc == Bytecodes::_jsr_w, "must be jsr"); 265 // 266 // // the real returnAddress is the bytecode following the jsr 267 // return new StackValue((intptr_t)(bci + Bytecodes::length_for(bc))); 268 } else if (VM.getVM().isLP64() && loc.holdsLong()) { 269 if ( loc.isRegister() ) { 270 // Long value in two registers, high half in the first, low in the second 271 return new StackValue(((valueAddr.getJLongAt(0) & 0xFFFFFFFF) << 32) | 272 ((valueAddr.getJLongAt(8) & 0xFFFFFFFF))); 273 } else { 274 // Long value in a single stack slot 275 return new StackValue(valueAddr.getJLongAt(0)); 276 } 277 } else if( loc.isRegister() ) { 278 // At the moment, all non-oop values in registers are 4 bytes, 279 // including double and long halves (see Compile::FillLocArray() in 280 // opto/output.cpp). Haul them out as such and return a StackValue 281 // containing an image of the value as it appears in a stack slot. 282 // If this is a double or long half, the interpreter _must_ deal 283 // with doubles and longs as entities split across two stack slots. 284 // To change this so doubles and/or longs can live in one stack slot, 285 // a StackValue will have to understand that it can contain an 286 // undivided double or long, implying that a Location (and the debug 287 // info mechanism) and FillLocArray() will also have to understand it. 288 return new StackValue(valueAddr.getJIntAt(0) & 0xFFFFFFFF); 289 } else { 290 return new StackValue(valueAddr.getJIntAt(0) & 0xFFFFFFFF); 291 } 292 } else if (sv.isConstantInt()) { 293 // Constant int: treat same as register int. 294 return new StackValue(((ConstantIntValue) sv).getValue() & 0xFFFFFFFF); 295 } else if (sv.isConstantOop()) { 296 // constant oop 297 return new StackValue(((ConstantOopReadValue) sv).getValue(), 0); 298 } else if (sv.isConstantDouble()) { 299 // Constant double in a single stack slot 300 double d = ((ConstantDoubleValue) sv).getValue(); 301 return new StackValue(Double.doubleToLongBits(d) & 0xFFFFFFFF); 302 } else if (VM.getVM().isLP64() && sv.isConstantLong()) { 303 // Constant long in a single stack slot 304 return new StackValue(((ConstantLongValue) sv).getValue() & 0xFFFFFFFF); 305 } else if (sv.isObject()) { 306 // Scalar replaced object in compiled frame 307 return new StackValue(((ObjectValue)sv).getValue(), 1); 308 } 309 310 // Unknown ScopeValue type 311 Assert.that(false, "Should not reach here"); 312 return new StackValue(0); // dummy 313 } 314 315 private BasicLock resolveMonitorLock(Location location) { 316 if (Assert.ASSERTS_ENABLED) { 317 Assert.that(location.isStack(), "for now we only look at the stack"); 318 } 319 int byteOffset = location.getStackOffset(); 320 // (stack picture) 321 // high: [ ] byte_offset + wordSize 322 // low [ ] byte_offset 323 // 324 // sp-> [ ] 0 325 // the byte_offset is the distance from the stack pointer to the lowest address 326 // The frame's original stack pointer, before any extension by its callee 327 // (due to Compiler1 linkage on SPARC), must be used. 328 return new BasicLock(getFrame().getUnextendedSP().addOffsetTo(byteOffset)); 329 } 330 }