1 /*
2  * Copyright (c) 1998, 2018, 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.Location;
30 import com.sun.jdi.Method;
31 import com.sun.jdi.ReferenceType;
32 import com.sun.jdi.VirtualMachine;
33 
34 public class LocationImpl extends MirrorImpl implements Location {
35     private final ReferenceTypeImpl declaringType;
36     private Method method;
37     private long methodRef;
38     private long codeIndex;
39     private LineInfo baseLineInfo = null;
40     private LineInfo otherLineInfo = null;
41 
LocationImpl(VirtualMachine vm, Method method, long codeIndex)42     LocationImpl(VirtualMachine vm, Method method, long codeIndex) {
43         super(vm);
44         this.method = method;
45         this.codeIndex = method.isNative()? -1 : codeIndex;
46         this.declaringType = (ReferenceTypeImpl)method.declaringType();
47     }
48 
49     /*
50      * This constructor allows lazy creation of the method mirror. This
51      * can be a performance savings if the method mirror does not yet
52      * exist.
53      */
LocationImpl(VirtualMachine vm, ReferenceTypeImpl declaringType, long methodRef, long codeIndex)54     LocationImpl(VirtualMachine vm, ReferenceTypeImpl declaringType,
55                  long methodRef, long codeIndex) {
56         super(vm);
57 
58         this.method = null;
59         this.codeIndex = codeIndex;
60         this.declaringType = declaringType;
61         this.methodRef = methodRef;
62     }
63 
equals(Object obj)64     public boolean equals(Object obj) {
65         if ((obj != null) && (obj instanceof Location)) {
66             Location other = (Location)obj;
67             return (method().equals(other.method())) &&
68                    (codeIndex() == other.codeIndex()) &&
69                    super.equals(obj);
70         } else {
71             return false;
72         }
73     }
74 
hashCode()75     public int hashCode() {
76         /*
77          * TO DO: better hash code?
78          */
79         return method().hashCode() + (int)codeIndex();
80     }
81 
compareTo(Location other)82     public int compareTo(Location other) {
83         int rc = method().compareTo(other.method());
84         if (rc == 0) {
85             long diff = codeIndex() - other.codeIndex();
86             if (diff < 0)
87                 return -1;
88             else if (diff > 0)
89                 return 1;
90             else
91                 return 0;
92         }
93         return rc;
94     }
95 
declaringType()96     public ReferenceType declaringType() {
97         return declaringType;
98     }
99 
method()100     public Method method() {
101         if (method == null) {
102             method = declaringType.getMethodMirror(methodRef);
103             if (method.isNative()) {
104                 codeIndex = -1;
105             }
106         }
107         return method;
108     }
109 
codeIndex()110     public long codeIndex() {
111         method();  // be sure information is up-to-date
112         return codeIndex;
113     }
114 
getBaseLineInfo(SDE.Stratum stratum)115     LineInfo getBaseLineInfo(SDE.Stratum stratum) {
116         LineInfo lineInfo;
117 
118         /* check if there is cached info to use */
119         if (baseLineInfo != null) {
120             return baseLineInfo;
121         }
122 
123         /* compute the line info */
124         MethodImpl methodImpl = (MethodImpl)method();
125         lineInfo = methodImpl.codeIndexToLineInfo(stratum, codeIndex());
126 
127         /* cache it */
128         addBaseLineInfo(lineInfo);
129 
130         return lineInfo;
131     }
132 
getLineInfo(SDE.Stratum stratum)133     LineInfo getLineInfo(SDE.Stratum stratum) {
134         LineInfo lineInfo;
135 
136         /* base stratum is done slighly differently */
137         if (stratum.isJava()) {
138             return getBaseLineInfo(stratum);
139         }
140 
141         /* check if there is cached info to use */
142         lineInfo = otherLineInfo; // copy because of concurrency
143         if (lineInfo != null && stratum.id().equals(lineInfo.liStratum())) {
144             return lineInfo;
145         }
146 
147         int baseLineNumber = lineNumber(SDE.BASE_STRATUM_NAME);
148         SDE.LineStratum lineStratum =
149                   stratum.lineStratum(declaringType, baseLineNumber);
150 
151         if (lineStratum != null && lineStratum.lineNumber() != -1) {
152             lineInfo = new StratumLineInfo(stratum.id(),
153                                            lineStratum.lineNumber(),
154                                            lineStratum.sourceName(),
155                                            lineStratum.sourcePath());
156         } else {
157             /* find best match */
158             MethodImpl methodImpl = (MethodImpl)method();
159             lineInfo = methodImpl.codeIndexToLineInfo(stratum, codeIndex());
160         }
161 
162         /* cache it */
163         addStratumLineInfo(lineInfo);
164 
165         return lineInfo;
166     }
167 
addStratumLineInfo(LineInfo lineInfo)168     void addStratumLineInfo(LineInfo lineInfo) {
169         otherLineInfo = lineInfo;
170     }
171 
addBaseLineInfo(LineInfo lineInfo)172     void addBaseLineInfo(LineInfo lineInfo) {
173         baseLineInfo = lineInfo;
174     }
175 
sourceName()176     public String sourceName() throws AbsentInformationException {
177         return sourceName(vm.getDefaultStratum());
178     }
179 
sourceName(String stratumID)180     public String sourceName(String stratumID)
181                                throws AbsentInformationException {
182         return sourceName(declaringType.stratum(stratumID));
183     }
184 
sourceName(SDE.Stratum stratum)185     String sourceName(SDE.Stratum stratum)
186                                throws AbsentInformationException {
187         return getLineInfo(stratum).liSourceName();
188     }
189 
sourcePath()190     public String sourcePath() throws AbsentInformationException {
191         return sourcePath(vm.getDefaultStratum());
192     }
193 
sourcePath(String stratumID)194     public String sourcePath(String stratumID)
195                                throws AbsentInformationException {
196         return sourcePath(declaringType.stratum(stratumID));
197     }
198 
sourcePath(SDE.Stratum stratum)199     String sourcePath(SDE.Stratum stratum)
200                                throws AbsentInformationException {
201         return getLineInfo(stratum).liSourcePath();
202     }
203 
lineNumber()204     public int lineNumber() {
205         return lineNumber(vm.getDefaultStratum());
206     }
207 
lineNumber(String stratumID)208     public int lineNumber(String stratumID) {
209         return lineNumber(declaringType.stratum(stratumID));
210     }
211 
lineNumber(SDE.Stratum stratum)212     int lineNumber(SDE.Stratum stratum) {
213         return getLineInfo(stratum).liLineNumber();
214     }
215 
toString()216     public String toString() {
217         if (lineNumber() == -1) {
218             return method().toString() + "+" + codeIndex();
219         } else {
220             return declaringType().name() + ":" + lineNumber();
221         }
222     }
223 }
224