1/*
2 * Copyright (c) 2000, 2012, 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
25package sun.jvm.hotspot.code;
26
27import java.io.*;
28import java.util.*;
29
30import sun.jvm.hotspot.debugger.*;
31import sun.jvm.hotspot.oops.*;
32import sun.jvm.hotspot.runtime.*;
33import 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
39public 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 = stream.readMethod();
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 = stream.readMethod();
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}
214