Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java
41161 views
/*1* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324package sun.jvm.hotspot.runtime;2526import java.util.*;27import sun.jvm.hotspot.code.*;28import sun.jvm.hotspot.debugger.*;29import sun.jvm.hotspot.oops.*;30import sun.jvm.hotspot.utilities.*;3132/** FIXME: missing many accessors; all we have right now is the method33and BCI. NOTE that this has been modified from the VM's version to34handle NULL ScopeDescs for the debugging case. This simplifies35using code a great deal. */3637public class CompiledVFrame extends JavaVFrame {38private ScopeDesc scope;39private boolean mayBeImprecise;4041public CompiledVFrame(Frame fr, RegisterMap regMap, JavaThread thread, ScopeDesc scope, boolean mayBeImprecise) {42super(fr, regMap, thread);43this.scope = scope;44this.mayBeImprecise = mayBeImprecise;45if (!VM.getVM().isDebugging()) {46Assert.that(scope != null, "scope must be present");47}48}4950public boolean isTop() {51if (VM.getVM().isDebugging()) {52return (getScope() == null || getScope().isTop());53} else {54return getScope().isTop();55}56}5758public boolean isCompiledFrame() {59return true;60}6162public boolean isDeoptimized() {63return fr.isDeoptimized();64}6566public boolean mayBeImpreciseDbg() {67return mayBeImprecise;68}6970/** Returns the active method */71public NMethod getCode() {72return VM.getVM().getCodeCache().findNMethod(fr.getPC());73}7475/** Returns the active method. Does not perform a guarantee76regarding unloaded methods -- more suitable for debugging77system. */78public NMethod getCodeUnsafe() {79return VM.getVM().getCodeCache().findNMethodUnsafe(fr.getPC());80}8182/** Returns the ScopeDesc */83public ScopeDesc getScope() {84return scope;85}8687public Method getMethod() {88if (VM.getVM().isDebugging() && getScope() == null) {89return getCodeUnsafe().getMethod();90}91return getScope().getMethod();92}9394public StackValueCollection getLocals() {95if (getScope() == null)96return new StackValueCollection();97List<ScopeValue> scvList = getScope().getLocals();98if (scvList == null)99return new StackValueCollection();100101// scvList is the list of ScopeValues describing the JVM stack state.102// There is one scv_list entry for every JVM stack state in use.103int length = scvList.size();104StackValueCollection result = new StackValueCollection(length);105for( int i = 0; i < length; i++ )106result.add( createStackValue(scvList.get(i)) );107108return result;109}110111public StackValueCollection getExpressions() {112if (getScope() == null)113return new StackValueCollection();114List<ScopeValue> scvList = getScope().getExpressions();115if (scvList == null)116return new StackValueCollection();117118// scvList is the list of ScopeValues describing the JVM stack state.119// There is one scv_list entry for every JVM stack state in use.120int length = scvList.size();121StackValueCollection result = new StackValueCollection(length);122for( int i = 0; i < length; i++ )123result.add( createStackValue(scvList.get(i)) );124125return result;126}127128public List<MonitorInfo> getMonitors() {129if (getScope() == null) {130return new ArrayList<>();131}132List<MonitorValue> monitors = getScope().getMonitors();133if (monitors == null) {134return new ArrayList<>();135}136List<MonitorInfo> result = new ArrayList<>(monitors.size());137for (int i = 0; i < monitors.size(); i++) {138MonitorValue mv = monitors.get(i);139ScopeValue ov = mv.owner();140StackValue ownerSV = createStackValue(ov); // it is an oop141if (ov.isObject()) { // The owner object was scalar replaced142Assert.that(mv.eliminated() && ownerSV.objIsScalarReplaced(), "monitor should be eliminated for scalar replaced object");143// Put klass for scalar replaced object.144ScopeValue kv = ((ObjectValue)ov).getKlass();145Assert.that(kv.isConstantOop(), "klass should be oop constant for scalar replaced object");146OopHandle k = ((ConstantOopReadValue)kv).getValue();147result.add(new MonitorInfo(k, resolveMonitorLock(mv.basicLock()), mv.eliminated(), true));148} else {149result.add(new MonitorInfo(ownerSV.getObject(), resolveMonitorLock(mv.basicLock()), mv.eliminated(), false));150}151}152return result;153}154155public int getBCI() {156int raw = getRawBCI();157return ((raw == DebugInformationRecorder.SYNCHRONIZATION_ENTRY_BCI) ? 0 : raw);158}159160/** Returns SynchronizationEntryBCI or bci() (used for synchronization) */161public int getRawBCI() {162if (VM.getVM().isDebugging() && getScope() == null) {163return 0; // No debugging information!164}165return getScope().getBCI();166}167168/** Returns the sender vframe */169public VFrame sender() {170if (Assert.ASSERTS_ENABLED) {171Assert.that(isTop(), "just checking");172}173return sender(false);174}175176public VFrame sender(boolean mayBeImprecise) {177if (!VM.getVM().isDebugging()) {178if (Assert.ASSERTS_ENABLED) {179Assert.that(scope != null, "When new stub generator is in place, then scope can never be NULL");180}181}182Frame f = (Frame) getFrame().clone();183return (isTop()184? super.sender(false)185: new CompiledVFrame(f, getRegisterMap(), getThread(), getScope().sender(), mayBeImprecise));186}187188private StackValue createStackValue(ScopeValue sv) {189// FIXME: this code appears to be out-of-date with respect to the VM especially in 64-bit mode190if (sv.isLocation()) {191// Stack or register value192Location loc = ((LocationValue) sv).getLocation();193194if (loc.isIllegal()) return new StackValue();195196// First find address of value197Address valueAddr = loc.isRegister()198// Value was in a callee-save register199? getRegisterMap().getLocation(new VMReg(loc.getRegisterNumber()))200// Else value was directly saved on the stack. The frame's original stack pointer,201// before any extension by its callee (due to Compiler1 linkage on SPARC), must be used.202: ((Address)fr.getUnextendedSP()).addOffsetTo(loc.getStackOffset());203204// Then package it right depending on type205if (loc.holdsFloat()) { // Holds a float in a double register?206// The callee has no clue whether the register holds a float,207// double or is unused. He always saves a double. Here we know208// a double was saved, but we only want a float back. Narrow the209// saved double to the float that the JVM wants.210if (Assert.ASSERTS_ENABLED) {211Assert.that( loc.isRegister(), "floats always saved to stack in 1 word" );212}213float value = (float) valueAddr.getJDoubleAt(0);214return new StackValue(Float.floatToIntBits(value) & 0xFFFFFFFF); // 64-bit high half is stack junk215} else if (loc.holdsInt()) { // Holds an int in a long register?216// The callee has no clue whether the register holds an int,217// long or is unused. He always saves a long. Here we know218// a long was saved, but we only want an int back. Narrow the219// saved long to the int that the JVM wants.220if (Assert.ASSERTS_ENABLED) {221Assert.that( loc.isRegister(), "ints always saved to stack in 1 word" );222}223return new StackValue(valueAddr.getJLongAt(0) & 0xFFFFFFFF);224} else if (loc.holdsNarrowOop()) { // Holds an narrow oop?225if (loc.isRegister() && VM.getVM().isBigEndian()) {226// The callee has no clue whether the register holds an narrow oop,227// long or is unused. He always saves a long. Here we know228// a long was saved, but we only want an narrow oop back. Narrow the229// saved long to the narrow oop that the JVM wants.230return new StackValue(valueAddr.getCompOopHandleAt(VM.getVM().getIntSize()), 0);231} else {232return new StackValue(valueAddr.getCompOopHandleAt(0), 0);233}234} else if( loc.holdsOop() ) { // Holds an oop?235return new StackValue(valueAddr.getOopHandleAt(0), 0);236} else if( loc.holdsDouble() ) {237// Double value in a single stack slot238return new StackValue(valueAddr.getJIntAt(0) & 0xFFFFFFFF);239} else if(loc.holdsAddr()) {240if (Assert.ASSERTS_ENABLED) {241Assert.that(!VM.getVM().isServerCompiler(), "No address type for locations with C2 (jsr-s are inlined)");242}243// FIXME: not yet implemented (no access to safepoint state yet)244return new StackValue(0);245// intptr_t return_addr_tmp = *(intptr_t *)value_addr;246// int bci = -1;247// // Get the bci of the jsr that generated this returnAddress value.248// // If the destination of a jsr is a block that ends with a return or throw, then249// // the GraphBuilder converts the jsr into a direct goto. This has the side effect that250// // the return address for the jsr gets emitted as a bci instead of as a real pc251// if (code()->contains((address)return_addr_tmp)) {252// ScopeDesc* scope = code()->scope_desc_at((address)(return_addr_tmp - jsr_call_offset), false);253// bci = scope->bci();254// } else {255// bci = (int)return_addr_tmp;256// }257// // no need to lock method as this happens at Safepoint258// assert (SafepointSynchronize::is_at_safepoint(), "must be at safepoint, otherwise lock method()");259// // make sure bci points to jsr260// Bytecode* bytecode = Bytecode_at(method()->bcp_from(bci));261// Bytecodes::Code bc = bytecode->code();262// assert (bc == Bytecodes::_jsr || bc == Bytecodes::_jsr_w, "must be jsr");263//264// // the real returnAddress is the bytecode following the jsr265// return new StackValue((intptr_t)(bci + Bytecodes::length_for(bc)));266} else if (VM.getVM().isLP64() && loc.holdsLong()) {267if ( loc.isRegister() ) {268// Long value in two registers, high half in the first, low in the second269return new StackValue(((valueAddr.getJLongAt(0) & 0xFFFFFFFF) << 32) |270((valueAddr.getJLongAt(8) & 0xFFFFFFFF)));271} else {272// Long value in a single stack slot273return new StackValue(valueAddr.getJLongAt(0));274}275} else if( loc.isRegister() ) {276// At the moment, all non-oop values in registers are 4 bytes,277// including double and long halves (see Compile::FillLocArray() in278// opto/output.cpp). Haul them out as such and return a StackValue279// containing an image of the value as it appears in a stack slot.280// If this is a double or long half, the interpreter _must_ deal281// with doubles and longs as entities split across two stack slots.282// To change this so doubles and/or longs can live in one stack slot,283// a StackValue will have to understand that it can contain an284// undivided double or long, implying that a Location (and the debug285// info mechanism) and FillLocArray() will also have to understand it.286return new StackValue(valueAddr.getJIntAt(0) & 0xFFFFFFFF);287} else {288return new StackValue(valueAddr.getJIntAt(0) & 0xFFFFFFFF);289}290} else if (sv.isConstantInt()) {291// Constant int: treat same as register int.292return new StackValue(((ConstantIntValue) sv).getValue() & 0xFFFFFFFF);293} else if (sv.isConstantOop()) {294// constant oop295return new StackValue(((ConstantOopReadValue) sv).getValue(), 0);296} else if (sv.isConstantDouble()) {297// Constant double in a single stack slot298double d = ((ConstantDoubleValue) sv).getValue();299return new StackValue(Double.doubleToLongBits(d) & 0xFFFFFFFF);300} else if (VM.getVM().isLP64() && sv.isConstantLong()) {301// Constant long in a single stack slot302return new StackValue(((ConstantLongValue) sv).getValue() & 0xFFFFFFFF);303} else if (sv.isObject()) {304// Scalar replaced object in compiled frame305return new StackValue(((ObjectValue)sv).getValue(), 1);306}307308// Unknown ScopeValue type309Assert.that(false, "Should not reach here");310return new StackValue(0); // dummy311}312313private BasicLock resolveMonitorLock(Location location) {314if (Assert.ASSERTS_ENABLED) {315Assert.that(location.isStack(), "for now we only look at the stack");316}317int byteOffset = location.getStackOffset();318// (stack picture)319// high: [ ] byte_offset + wordSize320// low [ ] byte_offset321//322// sp-> [ ] 0323// the byte_offset is the distance from the stack pointer to the lowest address324// The frame's original stack pointer, before any extension by its callee325// (due to Compiler1 linkage on SPARC), must be used.326return new BasicLock(getFrame().getUnextendedSP().addOffsetTo(byteOffset));327}328}329330331