1 /*
   2  * Copyright (c) 2004, 2016, 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 
  25 package sun.jvm.hotspot.utilities.soql;
  26 
  27 import java.util.*;
  28 import javax.script.ScriptException;
  29 import sun.jvm.hotspot.debugger.*;
  30 import sun.jvm.hotspot.classfile.*;
  31 import sun.jvm.hotspot.memory.*;
  32 import sun.jvm.hotspot.oops.*;
  33 import sun.jvm.hotspot.runtime.*;
  34 import sun.jvm.hotspot.utilities.*;
  35 import java.lang.reflect.Method;
  36 
  37 public 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 }