1 /*
2  * Copyright (c) 1998, 2017, 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.tools.jdi;
27 
28 import com.sun.jdi.AbsentInformationException;
29 import com.sun.jdi.ClassNotLoadedException;
30 import com.sun.jdi.InternalException;
31 import com.sun.jdi.LocalVariable;
32 import com.sun.jdi.Location;
33 import com.sun.jdi.Method;
34 import com.sun.jdi.StackFrame;
35 import com.sun.jdi.Type;
36 import com.sun.jdi.VirtualMachine;
37 
38 public class LocalVariableImpl extends MirrorImpl
39                                implements LocalVariable, ValueContainer
40 {
41     private final Method method;
42     private final int slot;
43     private final Location scopeStart;
44     private final Location scopeEnd;
45     private final String name;
46     private final String signature;
47     private String genericSignature = null;
48 
LocalVariableImpl(VirtualMachine vm, Method method, int slot, Location scopeStart, Location scopeEnd, String name, String signature, String genericSignature)49     LocalVariableImpl(VirtualMachine vm, Method method,
50                       int slot, Location scopeStart, Location scopeEnd,
51                       String name, String signature,
52                       String genericSignature) {
53         super(vm);
54         this.method = method;
55         this.slot = slot;
56         this.scopeStart = scopeStart;
57         this.scopeEnd = scopeEnd;
58         this.name = name;
59         this.signature = signature;
60         if (genericSignature != null && genericSignature.length() > 0) {
61             this.genericSignature = genericSignature;
62         } else {
63             // The Spec says to return null for non-generic types
64             this.genericSignature = null;
65         }
66     }
67 
equals(Object obj)68     public boolean equals(Object obj) {
69         if ((obj != null) && (obj instanceof LocalVariableImpl)) {
70             LocalVariableImpl other = (LocalVariableImpl)obj;
71             return ((slot() == other.slot()) &&
72                     (scopeStart != null) &&
73                     (scopeStart.equals(other.scopeStart)) &&
74                     (super.equals(obj)));
75         } else {
76             return false;
77         }
78     }
79 
hashCode()80     public int hashCode() {
81         /*
82          * TO DO: Better hash code
83          */
84         return ((scopeStart.hashCode() << 4) + slot());
85     }
86 
compareTo(LocalVariable object)87     public int compareTo(LocalVariable object) {
88         LocalVariableImpl other = (LocalVariableImpl)object;
89 
90         int rc = scopeStart.compareTo(other.scopeStart);
91         if (rc == 0) {
92             rc = slot() - other.slot();
93         }
94         return rc;
95     }
96 
name()97     public String name() {
98         return name;
99     }
100 
101     /**
102      * @return a text representation of the declared type
103      * of this variable.
104      */
typeName()105     public String typeName() {
106         JNITypeParser parser = new JNITypeParser(signature);
107         return parser.typeName();
108     }
109 
type()110     public Type type() throws ClassNotLoadedException {
111         return findType(signature());
112     }
113 
findType(String signature)114     public Type findType(String signature) throws ClassNotLoadedException {
115         ReferenceTypeImpl enclosing = (ReferenceTypeImpl)method.declaringType();
116         return enclosing.findType(signature);
117     }
118 
signature()119     public String signature() {
120         return signature;
121     }
122 
genericSignature()123     public String genericSignature() {
124         return genericSignature;
125     }
126 
isVisible(StackFrame frame)127     public boolean isVisible(StackFrame frame) {
128         validateMirror(frame);
129         Method frameMethod = frame.location().method();
130 
131         if (!frameMethod.equals(method)) {
132             throw new IllegalArgumentException(
133                        "frame method different than variable's method");
134         }
135 
136         // this is here to cover the possibility that we will
137         // allow LocalVariables for native methods.  If we do
138         // so we will have to re-examinine this.
139         if (frameMethod.isNative()) {
140             return false;
141         }
142 
143         return ((scopeStart.compareTo(frame.location()) <= 0)
144              && (scopeEnd.compareTo(frame.location()) >= 0));
145     }
146 
isArgument()147     public boolean isArgument() {
148         try {
149             MethodImpl method = (MethodImpl)scopeStart.method();
150             return (slot < method.argSlotCount());
151         } catch (AbsentInformationException e) {
152             // If this variable object exists, there shouldn't be absent info
153             throw new InternalException();
154         }
155     }
156 
slot()157     int slot() {
158         return slot;
159     }
160 
161     /*
162      * Compilers/VMs can have byte code ranges for variables of the
163      * same names that overlap. This is because the byte code ranges
164      * aren't necessarily scopes; they may have more to do with the
165      * lifetime of the variable's slot, depending on implementation.
166      *
167      * This method determines whether this variable hides an
168      * identically named variable; ie, their byte code ranges overlap
169      * this one starts after the given one. If it returns true this
170      * variable should be preferred when looking for a single variable
171      * with its name when both variables are visible.
172      */
hides(LocalVariable other)173     boolean hides(LocalVariable other) {
174         LocalVariableImpl otherImpl = (LocalVariableImpl)other;
175         if (!method.equals(otherImpl.method) ||
176             !name.equals(otherImpl.name)) {
177             return false;
178         } else {
179             return (scopeStart.compareTo(otherImpl.scopeStart) > 0);
180         }
181     }
182 
toString()183     public String toString() {
184        return name() + " in " + method.toString() +
185               "@" + scopeStart.toString();
186     }
187 }
188