1 /*
2  * Copyright (c) 2002, 2005, 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.jdi;
26 
27 import com.sun.jdi.*;
28 import sun.jvm.hotspot.oops.ObjectHeap;
29 import sun.jvm.hotspot.debugger.OopHandle;
30 import sun.jvm.hotspot.oops.Array;
31 import sun.jvm.hotspot.oops.ObjArray;
32 import sun.jvm.hotspot.oops.TypeArray;
33 import sun.jvm.hotspot.oops.Instance;
34 import sun.jvm.hotspot.runtime.BasicType;
35 import sun.jvm.hotspot.runtime.JavaVFrame;
36 import sun.jvm.hotspot.runtime.StackValue;
37 import sun.jvm.hotspot.runtime.StackValueCollection;
38 import sun.jvm.hotspot.utilities.Assert;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.ArrayList;
42 import java.util.HashMap;
43 import java.util.Iterator;
44 import java.util.Collections;
45 
46 public class StackFrameImpl extends MirrorImpl
47                             implements StackFrame
48 {
49     /* Once false, frame should not be used.
50      * access synchronized on (vm.state())
51      */
52     private boolean isValid = true;
53 
54     private final ThreadReferenceImpl thread;
55     private final JavaVFrame saFrame;
56     private final Location location;
57     private Map visibleVariables =  null;
58     private ObjectReference thisObject = null;
59 
StackFrameImpl(VirtualMachine vm, ThreadReferenceImpl thread, JavaVFrame jvf)60     StackFrameImpl(VirtualMachine vm, ThreadReferenceImpl thread,
61                    JavaVFrame jvf) {
62         super(vm);
63         this.thread = thread;
64         this.saFrame = jvf;
65 
66         sun.jvm.hotspot.oops.Method SAMethod = jvf.getMethod();
67 
68         ReferenceType rt = ((VirtualMachineImpl)vm).referenceType(SAMethod.getMethodHolder());
69 
70         this.location = new LocationImpl(vm, rt, SAMethod, (long)jvf.getBCI());
71     }
72 
validateStackFrame()73     private void validateStackFrame() {
74         if (!isValid) {
75             throw new InvalidStackFrameException("Thread has been resumed");
76         }
77     }
78 
getJavaVFrame()79     JavaVFrame getJavaVFrame() {
80         return saFrame;
81     }
82 
83     /**
84      * Return the frame location.
85      * Need not be synchronized since it cannot be provably stale.
86      */
location()87     public Location location() {
88         validateStackFrame();
89         return location;
90     }
91 
92     /**
93      * Return the thread holding the frame.
94      * Need not be synchronized since it cannot be provably stale.
95      */
thread()96     public ThreadReference thread() {
97         validateStackFrame();
98         return thread;
99     }
100 
equals(Object obj)101     public boolean equals(Object obj) {
102         if ((obj != null) && (obj instanceof StackFrameImpl)) {
103             StackFrameImpl other = (StackFrameImpl)obj;
104             return (saFrame.equals(other.saFrame));
105         } else {
106             return false;
107         }
108     }
109 
hashCode()110     public int hashCode() {
111         return saFrame.hashCode();
112     }
113 
thisObject()114     public ObjectReference thisObject() {
115         validateStackFrame();
116         MethodImpl currentMethod = (MethodImpl)location.method();
117         if (currentMethod.isStatic() || currentMethod.isNative()) {
118             return null;
119         }
120         if (thisObject == null) {
121             StackValueCollection values = saFrame.getLocals();
122             if (Assert.ASSERTS_ENABLED) {
123                 Assert.that(values.size() > 0, "this is missing");
124             }
125             // 'this' at index 0.
126             if (values.get(0).getType() == BasicType.getTConflict()) {
127               return null;
128             }
129             OopHandle handle = values.oopHandleAt(0);
130             ObjectHeap heap = vm.saObjectHeap();
131             thisObject = vm.objectMirror(heap.newOop(handle));
132         }
133         return thisObject;
134     }
135 
136     /**
137      * Build the visible variable map.
138      * Need not be synchronized since it cannot be provably stale.
139      */
createVisibleVariables()140     private void createVisibleVariables() throws AbsentInformationException {
141         if (visibleVariables == null) {
142             List allVariables = location.method().variables();
143             Map map = new HashMap(allVariables.size());
144 
145             Iterator iter = allVariables.iterator();
146             while (iter.hasNext()) {
147                 LocalVariableImpl variable = (LocalVariableImpl)iter.next();
148                 String name = variable.name();
149                 if (variable.isVisible(this)) {
150                     LocalVariable existing = (LocalVariable)map.get(name);
151                     if ((existing == null) ||
152                         variable.hides(existing)) {
153                         map.put(name, variable);
154                     }
155                 }
156             }
157             visibleVariables = map;
158         }
159     }
160 
161     /**
162      * Return the list of visible variable in the frame.
163      * Need not be synchronized since it cannot be provably stale.
164      */
visibleVariables()165     public List visibleVariables() throws AbsentInformationException {
166         validateStackFrame();
167         createVisibleVariables();
168         List mapAsList = new ArrayList(visibleVariables.values());
169         Collections.sort(mapAsList);
170         return mapAsList;
171     }
172 
173     /**
174      * Return a particular variable in the frame.
175      * Need not be synchronized since it cannot be provably stale.
176      */
visibleVariableByName(String name)177     public LocalVariable visibleVariableByName(String name) throws AbsentInformationException  {
178         validateStackFrame();
179         createVisibleVariables();
180         return (LocalVariable)visibleVariables.get(name);
181     }
182 
getValue(LocalVariable variable)183     public Value getValue(LocalVariable variable) {
184         List list = new ArrayList(1);
185         list.add(variable);
186         Map map = getValues(list);
187         return (Value)map.get(variable);
188     }
189 
getValues(List variables)190     public Map getValues(List variables) {
191         validateStackFrame();
192         StackValueCollection values = saFrame.getLocals();
193 
194         int count = variables.size();
195         Map map = new HashMap(count);
196         for (int ii=0; ii<count; ++ii) {
197             LocalVariableImpl variable = (LocalVariableImpl)variables.get(ii);
198             if (!variable.isVisible(this)) {
199                 throw new IllegalArgumentException(variable.name() +
200                                  " is not valid at this frame location");
201             }
202             ValueImpl valueImpl;
203             int ss = variable.slot();
204             char c = variable.signature().charAt(0);
205             BasicType variableType = BasicType.charToBasicType(c);
206             valueImpl = getSlotValue(values, variableType, ss);
207             map.put(variable, valueImpl);
208         }
209         return map;
210     }
211 
getArgumentValues()212     public List getArgumentValues() {
213         validateStackFrame();
214         StackValueCollection values = saFrame.getLocals();
215         MethodImpl mmm = (MethodImpl)location.method();
216         if (mmm.isNative())
217             return null;
218         List argSigs = mmm.argumentSignatures();
219         int count = argSigs.size();
220         List res = new ArrayList(0);
221 
222         int slot = mmm.isStatic()? 0 : 1;
223         for (int ii = 0; ii < count; ++slot, ++ii) {
224             char sigChar = ((String)argSigs.get(ii)).charAt(0);
225             BasicType variableType = BasicType.charToBasicType(sigChar);
226             res.add(getSlotValue(values, variableType, slot));
227             if (sigChar == 'J' || sigChar == 'D') {
228                 slot++;
229             }
230         }
231         return res;
232     }
233 
getSlotValue(StackValueCollection values, BasicType variableType, int ss)234     private ValueImpl getSlotValue(StackValueCollection values,
235                        BasicType variableType, int ss) {
236         ValueImpl valueImpl = null;
237         OopHandle handle = null;
238         ObjectHeap heap = vm.saObjectHeap();
239         if (values.get(ss).getType() == BasicType.getTConflict()) {
240           // Dead locals, so just represent them as a zero of the appropriate type
241           if (variableType == BasicType.T_BOOLEAN) {
242             valueImpl = (BooleanValueImpl) vm.mirrorOf(false);
243           } else if (variableType == BasicType.T_CHAR) {
244             valueImpl = (CharValueImpl) vm.mirrorOf((char)0);
245           } else if (variableType == BasicType.T_FLOAT) {
246             valueImpl = (FloatValueImpl) vm.mirrorOf((float)0);
247           } else if (variableType == BasicType.T_DOUBLE) {
248             valueImpl = (DoubleValueImpl) vm.mirrorOf((double)0);
249           } else if (variableType == BasicType.T_BYTE) {
250             valueImpl = (ByteValueImpl) vm.mirrorOf((byte)0);
251           } else if (variableType == BasicType.T_SHORT) {
252             valueImpl = (ShortValueImpl) vm.mirrorOf((short)0);
253           } else if (variableType == BasicType.T_INT) {
254             valueImpl = (IntegerValueImpl) vm.mirrorOf((int)0);
255           } else if (variableType == BasicType.T_LONG) {
256             valueImpl = (LongValueImpl) vm.mirrorOf((long)0);
257           } else if (variableType == BasicType.T_OBJECT) {
258             // we may have an [Ljava/lang/Object; - i.e., Object[] with the
259             // elements themselves may be arrays because every array is an Object.
260             handle = null;
261             valueImpl = (ObjectReferenceImpl) vm.objectMirror(heap.newOop(handle));
262           } else if (variableType == BasicType.T_ARRAY) {
263             handle = null;
264             valueImpl = vm.arrayMirror((Array)heap.newOop(handle));
265           } else if (variableType == BasicType.T_VOID) {
266             valueImpl = new VoidValueImpl(vm);
267           } else {
268             throw new RuntimeException("Should not read here");
269           }
270         } else {
271           if (variableType == BasicType.T_BOOLEAN) {
272             valueImpl = (BooleanValueImpl) vm.mirrorOf(values.booleanAt(ss));
273           } else if (variableType == BasicType.T_CHAR) {
274             valueImpl = (CharValueImpl) vm.mirrorOf(values.charAt(ss));
275           } else if (variableType == BasicType.T_FLOAT) {
276             valueImpl = (FloatValueImpl) vm.mirrorOf(values.floatAt(ss));
277           } else if (variableType == BasicType.T_DOUBLE) {
278             valueImpl = (DoubleValueImpl) vm.mirrorOf(values.doubleAt(ss));
279           } else if (variableType == BasicType.T_BYTE) {
280             valueImpl = (ByteValueImpl) vm.mirrorOf(values.byteAt(ss));
281           } else if (variableType == BasicType.T_SHORT) {
282             valueImpl = (ShortValueImpl) vm.mirrorOf(values.shortAt(ss));
283           } else if (variableType == BasicType.T_INT) {
284             valueImpl = (IntegerValueImpl) vm.mirrorOf(values.intAt(ss));
285           } else if (variableType == BasicType.T_LONG) {
286             valueImpl = (LongValueImpl) vm.mirrorOf(values.longAt(ss));
287           } else if (variableType == BasicType.T_OBJECT) {
288             // we may have an [Ljava/lang/Object; - i.e., Object[] with the
289             // elements themselves may be arrays because every array is an Object.
290             handle = values.oopHandleAt(ss);
291             valueImpl = (ObjectReferenceImpl) vm.objectMirror(heap.newOop(handle));
292           } else if (variableType == BasicType.T_ARRAY) {
293             handle = values.oopHandleAt(ss);
294             valueImpl = vm.arrayMirror((Array)heap.newOop(handle));
295           } else if (variableType == BasicType.T_VOID) {
296             valueImpl = new VoidValueImpl(vm);
297           } else {
298             throw new RuntimeException("Should not read here");
299           }
300         }
301 
302         return valueImpl;
303     }
304 
setValue(LocalVariable variableIntf, Value valueIntf)305     public void setValue(LocalVariable variableIntf, Value valueIntf)
306         throws InvalidTypeException, ClassNotLoadedException {
307 
308         vm.throwNotReadOnlyException("StackFrame.setValue()");
309     }
310 
toString()311     public String toString() {
312         return location.toString() + " in thread " + thread.toString();
313     }
314 }
315