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