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 }