diff agent/src/share/classes/sun/jvm/hotspot/utilities/soql/SOQLEngine.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/SOQLEngine.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2003-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.utilities.soql;
+
+import java.util.*;
+import sun.jvm.hotspot.oops.*;
+import sun.jvm.hotspot.memory.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.utilities.*;
+
+/**
+ * This is SOQL (Simple Object Query Language) engine. This
+ * uses JavaScript engine for the "select" and "where" expression
+ * parts.
+ */
+public class SOQLEngine extends JSJavaScriptEngine {
+   public static synchronized SOQLEngine getEngine() {
+      if (soleInstance == null) {
+         soleInstance = new SOQLEngine();
+      }
+      return soleInstance;
+   }
+
+   /**
+      Query is of the form
+
+         select <java script code to select>
+         [ from [instanceof] <class name> [<identifier>]
+           [ where <java script boolean expression> ]
+         ]
+   */
+   public synchronized void executeQuery(String query, ObjectVisitor visitor)
+                                                 throws SOQLException {
+      debugPrint("query : " + query);
+      StringTokenizer st = new StringTokenizer(query);
+      if (st.hasMoreTokens()) {
+         String first = st.nextToken();
+         if (! first.equals("select") ) {
+            throw new SOQLException("query syntax error: no 'select' clause");
+         }
+      } else {
+         throw new SOQLException("query syntax error: no 'select' clause");
+      }
+
+      int selectStart = query.indexOf("select");
+      int fromStart = query.indexOf("from");
+
+      String selectExpr = null;
+      String className = null;
+      boolean isInstanceOf = false;
+      String whereExpr = null;
+      String identifier = null;
+
+      if (fromStart != -1) {
+         selectExpr = query.substring(selectStart + "select".length(), fromStart);
+         st = new StringTokenizer(query.substring(fromStart + "from".length()));
+
+         if (st.hasMoreTokens()) {
+            String tmp = st.nextToken();
+            if (tmp.equals("instanceof")) {
+               isInstanceOf = true;
+               if (! st.hasMoreTokens()) {
+                  throw new SOQLException("no class name after 'instanceof'");
+               }
+               className = st.nextToken();
+            } else {
+               className = tmp;
+            }
+         } else {
+            throw new SOQLException("query syntax error: class name must follow 'from'");
+         }
+
+         if (st.hasMoreTokens()) {
+            identifier = st.nextToken();
+            if (identifier.equals("where")) {
+               throw new SOQLException("query syntax error: identifier should follow class name");
+            }
+            if (st.hasMoreTokens()) {
+               String tmp = st.nextToken();
+               if (! tmp.equals("where")) {
+                  throw new SOQLException("query syntax error: 'where' clause expected after 'from' clause");
+               }
+               int whereEnd = query.lastIndexOf("where") + 5; // "where".length
+               whereExpr = query.substring(whereEnd);
+            }
+         } else {
+            throw new SOQLException("query syntax error: identifier should follow class name");
+         }
+      } else { // no from clause
+         selectExpr = query.substring(selectStart + "select".length(), query.length());
+      }
+
+      executeQuery(new SOQLQuery(selectExpr, isInstanceOf, className, identifier, whereExpr), visitor);
+   }
+
+   private void executeQuery(SOQLQuery q, ObjectVisitor visitor) throws SOQLException {
+      InstanceKlass kls = null;
+      if (q.className != null) {
+         kls = SystemDictionaryHelper.findInstanceKlass(q.className);
+         if (kls == null) {
+            throw new SOQLException(q.className + " is not found!");
+         }
+      }
+
+
+      StringBuffer buf = new StringBuffer();
+      buf.append("function result(");
+      if (q.identifier != null) {
+         buf.append(q.identifier);
+      }
+      buf.append(") { return ");
+      buf.append(q.selectExpr.replace('\n', ' '));
+      buf.append("; }");
+
+      String selectCode = buf.toString();
+      debugPrint(selectCode);
+      String whereCode = null;
+      if (q.whereExpr != null) {
+         buf = new StringBuffer();
+         buf.append("function filter(");
+         buf.append(q.identifier);
+         buf.append(") { return ");
+         buf.append(q.whereExpr.replace('\n', ' '));
+         buf.append("; }");
+         whereCode = buf.toString();
+         debugPrint(whereCode);
+      } else {
+         whereCode = "filter = null;";
+      }
+
+      beginQuery();
+      // compile select expression and where condition
+      evalString(selectCode, "", 1);
+      evalString(whereCode,  "", 1);
+
+      // iterate thru heap, if needed
+      if (q.className != null) {
+         try {
+            iterateOops(kls, visitor, q.isInstanceOf);
+         } finally {
+            endQuery();
+         }
+      } else {
+         // simple "select <expr>" query
+         try {
+            Object select = call("result", new Object[] {});
+            visitor.visit(select);
+         } catch (Exception e) {
+            e.printStackTrace();
+         }
+      }
+   }
+
+   private void dispatchObject(Oop oop, ObjectVisitor visitor, boolean filterExists) {
+      JSJavaObject jsObj = factory.newJSJavaObject(oop);
+      Object[] args = new Object[] { jsObj };
+      boolean b = true;
+
+      try {
+         if (filterExists) {
+            Object res = call("filter", args);
+            if (res instanceof Boolean) {
+               b = ((Boolean)res).booleanValue();
+            } else if (res instanceof Number) {
+               b = ((Number)res).intValue() != 0;
+            } else {
+               b = (res != null);
+            }
+         }
+
+         if (b) {
+            Object select = call("result", args);
+            visitor.visit(select);
+         }
+      } catch (Exception e) {
+         throw new RuntimeException(e);
+      }
+   }
+
+   private void iterateOops(final InstanceKlass ik, final ObjectVisitor visitor,
+                            boolean includeSubtypes) {
+      ObjectHeap oh = VM.getVM().getObjectHeap();
+      oh.iterateObjectsOfKlass(new HeapVisitor() {
+                    boolean filterExists;
+                    public void prologue(long usedSize) {
+                        filterExists = getScriptEngine().get("filter") != null;
+                    }
+                    public boolean doObj(Oop obj) {
+                       dispatchObject(obj, visitor, filterExists);
+                       return false;
+                    }
+                    public void epilogue() {}
+                 }, ik, includeSubtypes);
+   }
+
+   // we create fresh ObjectReader and factory to avoid
+   // excessive cache across queries.
+   private void beginQuery() {
+      objReader = new ObjectReader();
+      factory = new JSJavaFactoryImpl();
+   }
+
+   // at the end of query we clear object reader cache
+   // and factory cache
+   private void endQuery() {
+      objReader = null;
+      factory = null;
+   }
+
+   protected ObjectReader getObjectReader() {
+      return objReader;
+   }
+
+   protected JSJavaFactory getJSJavaFactory() {
+      return factory;
+   }
+
+   protected boolean isQuitting() {
+      return false;
+   }
+
+   protected void quit() {
+      // do nothing
+   }
+
+   private static void debugPrint(String msg) {
+      if (debug) System.out.println(msg);
+   }
+
+   private static final boolean debug;
+   static {
+      debug = System.getProperty("sun.jvm.hotspot.utilities.soql.SOQLEngine.debug") != null;
+   }
+
+   protected SOQLEngine() {
+       super(debug);
+       start();
+   }
+
+   private ObjectReader objReader;
+   private JSJavaFactory factory;
+   private static SOQLEngine soleInstance;
+}