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