1/*
2 * Copyright (c) 2004, 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.
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 javax.script.ScriptException;
29import sun.jvm.hotspot.debugger.*;
30import sun.jvm.hotspot.classfile.*;
31import sun.jvm.hotspot.memory.*;
32import sun.jvm.hotspot.oops.*;
33import sun.jvm.hotspot.runtime.*;
34import sun.jvm.hotspot.utilities.*;
35import java.lang.reflect.Method;
36
37public class JSJavaHeap extends DefaultScriptObject {
38    private static final int FIELD_CAPACITY = 0;
39    private static final int FIELD_USED = 1;
40    private static final int FIELD_FOR_EACH_OBJECT = 2;
41    private static final int FIELD_FOR_EACH_CLASS = 3;
42
43    private static final int FIELD_UNDEFINED = -1;
44
45    public JSJavaHeap(JSJavaFactory fac) {
46        this.factory = fac;
47    }
48
49    public Object get(String name) {
50        int fieldID = getFieldID(name);
51        switch (fieldID) {
52        case FIELD_CAPACITY:
53            return new Long(getCapacity());
54        case FIELD_USED:
55            return new Long(getUsed());
56        case FIELD_FOR_EACH_OBJECT:
57            return new MethodCallable(this, forEachObjectMethod);
58        case FIELD_FOR_EACH_CLASS:
59            return new MethodCallable(this, forEachClassMethod);
60        case FIELD_UNDEFINED:
61        default:
62            return super.get(name);
63        }
64    }
65
66    public Object[] getIds() {
67        Object[] superIds = super.getIds();
68        Object[] tmp = fields.keySet().toArray();
69        Object[] res = new Object[superIds.length + tmp.length];
70        System.arraycopy(tmp, 0, res, 0, tmp.length);
71        System.arraycopy(superIds, 0, res, tmp.length, superIds.length);
72        return res;
73    }
74
75    public boolean has(String name) {
76        if (getFieldID(name) != FIELD_UNDEFINED) {
77            return true;
78        } else {
79            return super.has(name);
80        }
81    }
82
83    public void put(String name, Object value) {
84        if (getFieldID(name) == FIELD_UNDEFINED) {
85            super.put(name, value);
86        }
87    }
88
89    public void forEachObject(Object[] args) {
90        boolean subtypes = true;
91        Klass kls = null;
92        Callable func = null;
93        switch (args.length) {
94        case 3: {
95            Object b = args[2];
96            if (b != null && b instanceof Boolean) {
97                subtypes = ((Boolean)b).booleanValue();
98            }
99        }
100        case 2: {
101            Object k = args[1];
102            if (k == null) return;
103            if (k instanceof JSJavaKlass) {
104                kls = ((JSJavaKlass)k).getKlass();
105            } else if (k instanceof String) {
106                kls = SystemDictionaryHelper.findInstanceKlass((String)k);
107                if (kls == null) return;
108            }
109        }
110        case 1: {
111            Object f = args[0];
112            if (f != null && f instanceof Callable) {
113                func = (Callable) f;
114            } else {
115                // unknown target - just return
116                return ;
117            }
118        }
119        break;
120
121        default:
122            return;
123        }
124
125        final Callable finalFunc = func;
126      HeapVisitor visitor = new DefaultHeapVisitor() {
127                public boolean doObj(Oop oop) {
128                    JSJavaObject jo = factory.newJSJavaObject(oop);
129                    if (jo != null) {
130                  try {
131                    finalFunc.call(new Object[] { jo });
132                  } catch (ScriptException exp) {
133                    throw new RuntimeException(exp);
134                  }
135                    }
136                return false;
137                }
138            };
139        ObjectHeap heap = VM.getVM().getObjectHeap();
140        if (kls == null) {
141            kls = SystemDictionaryHelper.findInstanceKlass("java.lang.Object");
142        }
143        heap.iterateObjectsOfKlass(visitor, kls, subtypes);
144    }
145
146    public void forEachClass(Object[] args) {
147        boolean withLoader = false;
148        Callable func = null;
149        switch (args.length) {
150        case 2: {
151            Object b = args[1];
152            if (b instanceof Boolean) {
153                withLoader = ((Boolean)b).booleanValue();
154            }
155        }
156        case 1: {
157            Object f = args[0];
158            if (f instanceof Callable) {
159                func = (Callable) f;
160            } else {
161                return;
162            }
163        }
164        break;
165        default:
166            return;
167        }
168
169      final Callable finalFunc = func;
170        ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph();
171        if (withLoader) {
172            cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
173                    public void visit(Klass kls) {
174                        JSJavaKlass  jk = factory.newJSJavaKlass(kls);
175                        Oop loader = kls.getClassLoader();
176                        if (jk == null) {
177                            return;
178                        }
179                        JSJavaObject k = jk.getJSJavaClass();
180                        JSJavaObject l = factory.newJSJavaObject(loader);
181                        if (k != null) {
182                          if (l != null) {
183                            try {
184                              finalFunc.call(new Object[] { k, l });
185                            } catch (ScriptException exp) {
186                              throw new RuntimeException(exp);
187                            }
188                          }
189                       }
190                    }
191                });
192
193        } else {
194            cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() {
195                    public void visit(Klass kls) {
196                        JSJavaKlass jk = factory.newJSJavaKlass(kls);
197                        if (jk == null) {
198                            return;
199                        }
200                        JSJavaClass k = jk.getJSJavaClass();
201                        if (k != null) {
202                            if (k != null) {
203                        try {
204                                  finalFunc.call(new Object[] { k });
205                        } catch (ScriptException exp) {
206                          throw new RuntimeException(exp);
207                        }
208                            }
209                        }
210                    }
211                });
212        }
213    }
214
215    public String toString() {
216        StringBuffer buf = new StringBuffer();
217        buf.append("Java Heap (capacity=");
218        buf.append(getCapacity());
219        buf.append(", used=");
220        buf.append(getUsed());
221        buf.append(")");
222        return buf.toString();
223    }
224
225    //-- Internals only below this point
226    private static Map fields = new HashMap();
227    private static void addField(String name, int fieldId) {
228        fields.put(name, new Integer(fieldId));
229    }
230
231    private static int getFieldID(String name) {
232        Integer res = (Integer) fields.get(name);
233        return (res != null)? res.intValue() : FIELD_UNDEFINED;
234    }
235
236    static {
237        addField("capacity", FIELD_CAPACITY);
238        addField("used", FIELD_USED);
239        addField("forEachObject", FIELD_FOR_EACH_OBJECT);
240        addField("forEachClass", FIELD_FOR_EACH_CLASS);
241      try {
242          Class myClass = JSJavaHeap.class;
243          forEachObjectMethod = myClass.getMethod("forEachObject",
244                                new Class[] { Object[].class });
245          forEachClassMethod = myClass.getMethod("forEachClass",
246                                new Class[] {Object[].class });
247      } catch (RuntimeException re) {
248          throw re;
249      } catch (Exception exp) {
250          throw new RuntimeException(exp);
251      }
252    }
253
254    private long getCapacity() {
255        return VM.getVM().getUniverse().heap().capacity();
256    }
257
258    private long getUsed() {
259        return VM.getVM().getUniverse().heap().used();
260    }
261
262    private final JSJavaFactory factory;
263    private static Method forEachObjectMethod;
264    private static Method forEachClassMethod;
265}
266