1/*
2 * Copyright (c) 2004, 2012, 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
25package sun.jvm.hotspot.utilities.soql;
26
27import java.util.*;
28import sun.jvm.hotspot.debugger.*;
29import sun.jvm.hotspot.oops.*;
30import sun.jvm.hotspot.runtime.*;
31
32public class JSJavaFrame extends DefaultScriptObject {
33    private static final int FIELD_METHOD      = 0;
34    private static final int FIELD_BCI         = 1;
35    private static final int FIELD_LINE_NUMBER = 2;
36    private static final int FIELD_LOCALS      = 3;
37    private static final int FIELD_THIS_OBJECT = 4;
38    private static final int FIELD_THREAD      = 5;
39    private static final int FIELD_UNDEFINED   = -1;
40
41    public JSJavaFrame(JavaVFrame jvf, JSJavaFactory fac) {
42        this.jvf = jvf;
43        this.factory = fac;
44    }
45
46    public Object get(String name) {
47        int fieldID = getFieldID(name);
48        switch (fieldID) {
49        case FIELD_METHOD:
50            return getMethod();
51        case FIELD_BCI:
52            return new Integer(getBCI());
53        case FIELD_LINE_NUMBER:
54            return new Integer(getLineNumber());
55        case FIELD_LOCALS:
56            return getLocals();
57        case FIELD_THIS_OBJECT:
58            return getThisObject();
59        case FIELD_THREAD:
60            return getThread();
61        case FIELD_UNDEFINED:
62        default:
63            return super.get(name);
64        }
65    }
66
67    public Object[] getIds() {
68       Object[] fieldNames = fields.keySet().toArray();
69       Object[] superFields = super.getIds();
70       Object[] res = new Object[fieldNames.length + superFields.length];
71       System.arraycopy(fieldNames, 0, res, 0, fieldNames.length);
72       System.arraycopy(superFields, 0, res, fieldNames.length, superFields.length);
73       return res;
74   }
75
76    public boolean has(String name) {
77        if (getFieldID(name) != FIELD_UNDEFINED) {
78            return true;
79        } else {
80            return super.has(name);
81        }
82    }
83
84    public void put(String name, Object value) {
85        if (getFieldID(name) == FIELD_UNDEFINED) {
86            super.put(name, value);
87        }
88    }
89
90    public String toString() {
91        StringBuffer buf = new StringBuffer();
92        buf.append("Frame (method=");
93        buf.append(jvf.getMethod().externalNameAndSignature());
94        buf.append(", bci=");
95        buf.append(getBCI());
96        buf.append(", line=");
97        buf.append(getLineNumber());
98        buf.append(')');
99        return buf.toString();
100    }
101
102    //-- Internals only below this point
103    private static Map fields = new HashMap();
104    private static void addField(String name, int fieldId) {
105        fields.put(name, new Integer(fieldId));
106    }
107
108    private static int getFieldID(String name) {
109        Integer res = (Integer) fields.get(name);
110        return (res != null)? res.intValue() : FIELD_UNDEFINED;
111    }
112
113    static {
114        addField("method", FIELD_METHOD);
115        addField("bci", FIELD_BCI);
116        addField("line", FIELD_LINE_NUMBER);
117        addField("locals", FIELD_LOCALS);
118        addField("thisObject", FIELD_THIS_OBJECT);
119        addField("thread", FIELD_THREAD);
120    }
121
122    private JSJavaMethod getMethod() {
123        return factory.newJSJavaMethod(jvf.getMethod());
124    }
125
126    private int getBCI() {
127        return jvf.getBCI();
128    }
129
130    private int getLineNumber() {
131        int bci = jvf.getBCI();
132        if (bci == -1) {
133            return 0;
134        } else {
135            int lineNum = jvf.getMethod().getLineNumberFromBCI(bci);
136            return (lineNum <= 0)? 0 : lineNum;
137        }
138    }
139
140    private synchronized JSMap getLocals() {
141        if (localsCache == null) {
142            Map map = new HashMap();
143            localsCache = factory.newJSMap(map);
144            StackValueCollection values = jvf.getLocals();
145            Method method = jvf.getMethod();
146            if (method.isNative() || ! method.hasLocalVariableTable() ||
147                values == null) {
148                return localsCache;
149            }
150
151            LocalVariableTableElement[] localVars = method.getLocalVariableTable();
152            int bci = getBCI();
153            List visibleVars = new ArrayList(0);
154            for (int i = 0; i < localVars.length; i++) {
155                LocalVariableTableElement cur = localVars[i];
156                int startBCI = cur.getStartBCI();
157                if (startBCI <= bci && bci < startBCI + cur.getLength()) {
158                    visibleVars.add(cur);
159                }
160            }
161
162            OopHandle handle = null;
163            ObjectHeap heap = VM.getVM().getObjectHeap();
164            for (Iterator varItr = visibleVars.iterator(); varItr.hasNext();) {
165                LocalVariableTableElement cur = (LocalVariableTableElement) varItr.next();
166                String name =  method.getConstants().getSymbolAt(cur.getNameCPIndex()).asString();
167                int slot = cur.getSlot();
168
169                String signature = method.getConstants().getSymbolAt(cur.getDescriptorCPIndex()).asString();
170                BasicType variableType = BasicType.charToBasicType(signature.charAt(0));
171                Object value = null;
172                if (variableType == BasicType.T_BOOLEAN) {
173                    value = Boolean.valueOf(values.booleanAt(slot));
174                } else if (variableType == BasicType.T_CHAR) {
175                    value = new Character(values.charAt(slot));
176                } else if (variableType == BasicType.T_FLOAT) {
177                    value = new Float(values.floatAt(slot));
178                } else if (variableType == BasicType.T_DOUBLE) {
179                    value = new Double(values.doubleAt(slot));
180                } else if (variableType == BasicType.T_BYTE) {
181                    value = new Byte(values.byteAt(slot));
182                } else if (variableType == BasicType.T_SHORT) {
183                    value = new Short(values.shortAt(slot));
184                } else if (variableType == BasicType.T_INT) {
185                    value = new Integer(values.intAt(slot));
186                } else if (variableType == BasicType.T_LONG) {
187                    value = new Long(values.longAt(slot));
188                } else if (variableType == BasicType.T_OBJECT ||
189                       variableType == BasicType.T_ARRAY) {
190                    handle = values.oopHandleAt(slot);
191                    value = factory.newJSJavaObject(heap.newOop(handle));
192                } else {
193                    // ignore
194                }
195                map.put(name, value);
196            }
197        }
198        return localsCache;
199    }
200
201    private JSJavaObject getThisObject() {
202        Method method = jvf.getMethod();
203        if (method.isStatic()) {
204            return null;
205        }
206        StackValueCollection values = jvf.getLocals();
207        if (values != null) {
208            // 'this' at index 0.
209            OopHandle handle = values.oopHandleAt(0);
210            ObjectHeap heap = VM.getVM().getObjectHeap();
211            return factory.newJSJavaObject(heap.newOop(handle));
212        } else {
213            // can't get locals, return null.
214            return null;
215        }
216    }
217
218    private JSJavaThread getThread() {
219        return factory.newJSJavaThread(jvf.getThread());
220    }
221
222    private final JavaVFrame jvf;
223    private final JSJavaFactory factory;
224    private JSMap localsCache;
225}
226