1
/*
2
 * $Id$
3
 *
4
 * Copyright (C) 2003-2009 JNode.org
5
 *
6
 * This library is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation; either version 2.1 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful, but 
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
14
 * License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with this library; If not, write to the Free Software Foundation, Inc., 
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
 */
20
 
21
package org.jnode.vm;
22
23
import org.jnode.annotation.MagicPermission;
24
import org.jnode.vm.classmgr.VmCompiledCode;
25
import org.jnode.vm.classmgr.VmMethod;
26
import org.vmmagic.unboxed.Address;
27
28
@MagicPermission
29
final class VmStackFrameEnumerator {
30
31
    /**
32
     * Stack frame reader
33
     */
34
    private final VmStackReader reader;
35
    /**
36
     * Address of current stack frame
37
     */
38
    private Address framePtr;
39
    /**
40
     * Index in address map of current stack frame method (deals with inlined methods)
41
     */
42
    private int codeIndex;
43
    /**
44
     * Compiled code for the current frame
45
     */
46
    private VmCompiledCode cc;
47
48
    /**
49
     * Initialize this instance.
50
     *
51
     * @param reader
52
     * @param framePtr
53
     * @param instrPtr
54
     */
55
    public VmStackFrameEnumerator(VmStackReader reader, Address framePtr, Address instrPtr) {
56
        this.reader = reader;
57
        reset(framePtr, instrPtr);
58
    }
59
60
    /**
61
     * Initialize this instance.
62
     * Set the enumerator to enumerate the stack of the current thread.
63
     *
64
     * @param reader
65
     */
66
    public VmStackFrameEnumerator(VmStackReader reader) {
67
        this.reader = reader;
68
        final Address curFrame = VmMagic.getCurrentFrame();
69
        reset(reader.getPrevious(curFrame), reader.getReturnAddress(curFrame));
70
    }
71
72
    /**
73
     * Reset the enumerator to the given pointers.
74
     *
75
     * @param framePtr
76
     * @param instrPtr
77
     */
78
    public final void reset(Address framePtr, Address instrPtr) {
79
        this.framePtr = framePtr;
80
        initializeCodeIndex(instrPtr);
81
    }
82
83
    /**
84
     * Is the current frameptr valid.
85
     *
86
     * @return
87
     */
88
    public final boolean isValid() {
89
        return reader.isValid(framePtr);
90
    }
91
92
    /**
93
     * Move to the next stack position.
94
     */
95
    public final void next() {
96
        if (reader.isValid(framePtr)) {
97
            if (cc != null) {
98
                final int newIndex = cc.getAddressMap().getCallSiteIndex(codeIndex);
99
                if (newIndex >= 0) {
100
                    codeIndex = newIndex;
101
                    return;
102
                }
103
            }
104
            final Address nextIP = reader.getReturnAddress(framePtr).add(-1);
105
            this.framePtr = reader.getPrevious(framePtr);
106
            initializeCodeIndex(nextIP);
107
        }
108
    }
109
110
    /**
111
     * Gets the method at the current stack position.
112
     *
113
     * @return
114
     */
115
    public final VmMethod getMethod() {
116
        VmMethod m = null;
117
        if (cc != null) {
118
            m = cc.getAddressMap().getMethodAtIndex(codeIndex);
119
        }
120
        if (m == null) {
121
            m = cc.getMethod();
122
        }
123
        if (m == null) {
124
            m = reader.getMethod(framePtr);
125
        }
126
        return m;
127
    }
128
129
    /**
130
     * Gets the method at the current stack position.
131
     *
132
     * @return
133
     */
134
    public final int getProgramCounter() {
135
        if (cc != null) {
136
            return cc.getAddressMap().getProgramCounterAtIndex(codeIndex);
137
        } else {
138
            return -1;
139
        }
140
    }
141
142
    /**
143
     * Gets the line number at the current stack position.
144
     *
145
     * @return
146
     */
147
    public final int getLineNumber() {
148
        return getMethod().getBytecode().getLineNr(getProgramCounter());
149
    }
150
151
    private void initializeCodeIndex(Address instrPtr) {
152
        cc = reader.getCompiledCode(framePtr);
153
        if (cc != null) {
154
            codeIndex = cc.getAddressMapIndex(instrPtr);
155
        } else {
156
            codeIndex = -1;
157
        }
158
    }
159
}