1 /*
   2  * Copyright 2000-2005 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.code;
  26 
  27 import java.io.*;
  28 import java.util.*;
  29 
  30 import sun.jvm.hotspot.debugger.*;
  31 import sun.jvm.hotspot.oops.*;
  32 import sun.jvm.hotspot.runtime.*;
  33 import sun.jvm.hotspot.utilities.*;
  34 
  35 /** ScopeDescs contain the information that makes source-level
  36     debugging of nmethods possible; each scopeDesc describes a method
  37     activation */
  38 
  39 public class ScopeDesc {
  40   /** NMethod information */
  41   private NMethod code;
  42   private Method  method;
  43   private int     bci;
  44   /** Decoding offsets */
  45   private int     decodeOffset;
  46   private int     senderDecodeOffset;
  47   private int     localsDecodeOffset;
  48   private int     expressionsDecodeOffset;
  49   private int     monitorsDecodeOffset;
  50   /** Scalar replaced bjects pool */
  51   private List    objects; // ArrayList<ScopeValue>
  52 
  53 
  54   public ScopeDesc(NMethod code, int decodeOffset) {
  55     this.code = code;
  56     this.decodeOffset = decodeOffset;
  57     this.objects      = decodeObjectValues(DebugInformationRecorder.SERIALIZED_NULL);
  58 
  59     // Decode header
  60     DebugInfoReadStream stream  = streamAt(decodeOffset);
  61 
  62     senderDecodeOffset = stream.readInt();
  63     method = (Method) VM.getVM().getObjectHeap().newOop(stream.readOopHandle());
  64     bci    = stream.readBCI();
  65     // Decode offsets for body and sender
  66     localsDecodeOffset      = stream.readInt();
  67     expressionsDecodeOffset = stream.readInt();
  68     monitorsDecodeOffset    = stream.readInt();
  69   }
  70 
  71   public ScopeDesc(NMethod code, int decodeOffset, int objectDecodeOffset) {
  72     this.code = code;
  73     this.decodeOffset = decodeOffset;
  74     this.objects      = decodeObjectValues(objectDecodeOffset);
  75 
  76     // Decode header
  77     DebugInfoReadStream stream  = streamAt(decodeOffset);
  78 
  79     senderDecodeOffset = stream.readInt();
  80     method = (Method) VM.getVM().getObjectHeap().newOop(stream.readOopHandle());
  81     bci    = stream.readBCI();
  82     // Decode offsets for body and sender
  83     localsDecodeOffset      = stream.readInt();
  84     expressionsDecodeOffset = stream.readInt();
  85     monitorsDecodeOffset    = stream.readInt();
  86   }
  87 
  88   public NMethod getNMethod() { return code; }
  89   public Method getMethod() { return method; }
  90   public int    getBCI()    { return bci;    }
  91 
  92   /** Returns a List&lt;ScopeValue&gt; */
  93   public List getLocals() {
  94     return decodeScopeValues(localsDecodeOffset);
  95   }
  96 
  97   /** Returns a List&lt;ScopeValue&gt; */
  98   public List getExpressions() {
  99     return decodeScopeValues(expressionsDecodeOffset);
 100   }
 101 
 102   /** Returns a List&lt;MonitorValue&gt; */
 103   public List getMonitors() {
 104     return decodeMonitorValues(monitorsDecodeOffset);
 105   }
 106 
 107   /** Returns a List&lt;MonitorValue&gt; */
 108   public List getObjects() {
 109     return objects;
 110   }
 111 
 112   /** Stack walking. Returns null if this is the outermost scope. */
 113   public ScopeDesc sender() {
 114     if (isTop()) {
 115       return null;
 116     }
 117 
 118     return new ScopeDesc(code, senderDecodeOffset);
 119   }
 120 
 121   /** Returns where the scope was decoded */
 122   public int getDecodeOffset() {
 123     return decodeOffset;
 124   }
 125 
 126   /** Tells whether sender() returns null */
 127   public boolean isTop() {
 128     return (senderDecodeOffset == DebugInformationRecorder.SERIALIZED_NULL);
 129   }
 130 
 131   public boolean equals(Object arg) {
 132     if (arg == null) {
 133       return false;
 134     }
 135 
 136     if (!(arg instanceof ScopeDesc)) {
 137       return false;
 138     }
 139 
 140     ScopeDesc sd = (ScopeDesc) arg;
 141 
 142     return (sd.method.equals(method) && (sd.bci == bci));
 143   }
 144 
 145   public void printValue() {
 146     printValueOn(System.out);
 147   }
 148 
 149   public void printValueOn(PrintStream tty) {
 150     tty.print("ScopeDesc for ");
 151     method.printValueOn(tty);
 152     tty.println(" @bci " + bci);
 153   }
 154 
 155   // FIXME: add more accessors
 156 
 157   //--------------------------------------------------------------------------------
 158   // Internals only below this point
 159   //
 160 
 161   private DebugInfoReadStream streamAt(int decodeOffset) {
 162     return new DebugInfoReadStream(code, decodeOffset, objects);
 163   }
 164 
 165   /** Returns a List&lt;ScopeValue&gt; or null if no values were present */
 166   private List decodeScopeValues(int decodeOffset) {
 167     if (decodeOffset == DebugInformationRecorder.SERIALIZED_NULL) {
 168       return null;
 169     }
 170     DebugInfoReadStream stream = streamAt(decodeOffset);
 171     int length = stream.readInt();
 172     List res = new ArrayList(length);
 173     for (int i = 0; i < length; i++) {
 174       res.add(ScopeValue.readFrom(stream));
 175     }
 176     return res;
 177   }
 178 
 179   /** Returns a List&lt;MonitorValue&gt; or null if no values were present */
 180   private List decodeMonitorValues(int decodeOffset) {
 181     if (decodeOffset == DebugInformationRecorder.SERIALIZED_NULL) {
 182       return null;
 183     }
 184     DebugInfoReadStream stream = streamAt(decodeOffset);
 185     int length = stream.readInt();
 186     List res = new ArrayList(length);
 187     for (int i = 0; i < length; i++) {
 188       res.add(new MonitorValue(stream));
 189     }
 190     return res;
 191   }
 192 
 193   /** Returns a List&lt;ObjectValue&gt; or null if no values were present */
 194   private List decodeObjectValues(int decodeOffset) {
 195     if (decodeOffset == DebugInformationRecorder.SERIALIZED_NULL) {
 196       return null;
 197     }
 198     List res = new ArrayList();
 199     DebugInfoReadStream stream = new DebugInfoReadStream(code, decodeOffset, res);
 200     int length = stream.readInt();
 201     for (int i = 0; i < length; i++) {
 202       // Objects values are pushed to 'res' array during read so that
 203       // object's fields could reference it (OBJECT_ID_CODE).
 204       ScopeValue.readFrom(stream);
 205       // res.add(ScopeValue.readFrom(stream));
 206     }
 207     Assert.that(res.size() == length, "inconsistent debug information");
 208     return res;
 209   }
 210 }