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
26package com.sun.tools.jdi;
27
28import com.sun.jdi.AbsentInformationException;
29import com.sun.jdi.Location;
30import com.sun.jdi.Method;
31import com.sun.jdi.ReferenceType;
32import com.sun.jdi.VirtualMachine;
33
34public 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
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     */
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
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
75    public int hashCode() {
76        /*
77         * TO DO: better hash code?
78         */
79        return method().hashCode() + (int)codeIndex();
80    }
81
82    public int compareTo(Location object) {
83        LocationImpl other = (LocationImpl)object;
84        int rc = method().compareTo(other.method());
85        if (rc == 0) {
86            long diff = codeIndex() - other.codeIndex();
87            if (diff < 0)
88                return -1;
89            else if (diff > 0)
90                return 1;
91            else
92                return 0;
93        }
94        return rc;
95    }
96
97    public ReferenceType declaringType() {
98        return declaringType;
99    }
100
101    public Method method() {
102        if (method == null) {
103            method = declaringType.getMethodMirror(methodRef);
104            if (method.isNative()) {
105                codeIndex = -1;
106            }
107        }
108        return method;
109    }
110
111    public long codeIndex() {
112        method();  // be sure information is up-to-date
113        return codeIndex;
114    }
115
116    LineInfo getBaseLineInfo(SDE.Stratum stratum) {
117        LineInfo lineInfo;
118
119        /* check if there is cached info to use */
120        if (baseLineInfo != null) {
121            return baseLineInfo;
122        }
123
124        /* compute the line info */
125        MethodImpl methodImpl = (MethodImpl)method();
126        lineInfo = methodImpl.codeIndexToLineInfo(stratum, codeIndex());
127
128        /* cache it */
129        addBaseLineInfo(lineInfo);
130
131        return lineInfo;
132    }
133
134    LineInfo getLineInfo(SDE.Stratum stratum) {
135        LineInfo lineInfo;
136
137        /* base stratum is done slighly differently */
138        if (stratum.isJava()) {
139            return getBaseLineInfo(stratum);
140        }
141
142        /* check if there is cached info to use */
143        lineInfo = otherLineInfo; // copy because of concurrency
144        if (lineInfo != null && stratum.id().equals(lineInfo.liStratum())) {
145            return lineInfo;
146        }
147
148        int baseLineNumber = lineNumber(SDE.BASE_STRATUM_NAME);
149        SDE.LineStratum lineStratum =
150                  stratum.lineStratum(declaringType, baseLineNumber);
151
152        if (lineStratum != null && lineStratum.lineNumber() != -1) {
153            lineInfo = new StratumLineInfo(stratum.id(),
154                                           lineStratum.lineNumber(),
155                                           lineStratum.sourceName(),
156                                           lineStratum.sourcePath());
157        } else {
158            /* find best match */
159            MethodImpl methodImpl = (MethodImpl)method();
160            lineInfo = methodImpl.codeIndexToLineInfo(stratum, codeIndex());
161        }
162
163        /* cache it */
164        addStratumLineInfo(lineInfo);
165
166        return lineInfo;
167    }
168
169    void addStratumLineInfo(LineInfo lineInfo) {
170        otherLineInfo = lineInfo;
171    }
172
173    void addBaseLineInfo(LineInfo lineInfo) {
174        baseLineInfo = lineInfo;
175    }
176
177    public String sourceName() throws AbsentInformationException {
178        return sourceName(vm.getDefaultStratum());
179    }
180
181    public String sourceName(String stratumID)
182                               throws AbsentInformationException {
183        return sourceName(declaringType.stratum(stratumID));
184    }
185
186    String sourceName(SDE.Stratum stratum)
187                               throws AbsentInformationException {
188        return getLineInfo(stratum).liSourceName();
189    }
190
191    public String sourcePath() throws AbsentInformationException {
192        return sourcePath(vm.getDefaultStratum());
193    }
194
195    public String sourcePath(String stratumID)
196                               throws AbsentInformationException {
197        return sourcePath(declaringType.stratum(stratumID));
198    }
199
200    String sourcePath(SDE.Stratum stratum)
201                               throws AbsentInformationException {
202        return getLineInfo(stratum).liSourcePath();
203    }
204
205    public int lineNumber() {
206        return lineNumber(vm.getDefaultStratum());
207    }
208
209    public int lineNumber(String stratumID) {
210        return lineNumber(declaringType.stratum(stratumID));
211    }
212
213    int lineNumber(SDE.Stratum stratum) {
214        return getLineInfo(stratum).liLineNumber();
215    }
216
217    public String toString() {
218        if (lineNumber() == -1) {
219            return method().toString() + "+" + codeIndex();
220        } else {
221            return declaringType().name() + ":" + lineNumber();
222        }
223    }
224}
225