1 /*
   2  * Copyright 2000-2008 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);
 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         }
 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 }