diff agent/src/share/classes/sun/jvm/hotspot/jdi/SAJDIClassLoader.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c70a245cad3a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/jdi/SAJDIClassLoader.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2003-2004 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.jdi;
+
+import java.io.*;
+import java.net.*;
+
+/*
+ * This class loader is used for two different reasons:
+ *
+ * 1) To support multiple simultaneous debuggees.
+ *
+ * SA's architecture does not allow us to use multiple simultaneous
+ * debuggees. This is because of lots of static fields caching
+ * vmStruct fields and singleton assumption in classes such as
+ * 'sun.jvm.hotspot.runtime.VM'. Hence, we use instances of this
+ * class loader to create a separate namespace for each debuggee VM.
+ *
+ * 2) To support cross VM version debugging.
+ *
+ * SA has very close dependency on VM data structures. Due to this, a
+ * version of SA can only support debuggees running a same dot-dot release and
+ * update releases only. For eg. this version of SA supports only 1.4.2 and
+ * 1.4.2_xx releases only. But, users may want to debug debuggees running
+ * a different version of VM. To support this, we use an instance of this
+ * class loader to load classes from corresponding sa-jdi.jar.
+ *
+ * Note that JDI classes would still be loaded from the debugger's tools.jar
+ * and not from debuggee's tools.jar. This means that if JDI interface evolved
+ * b/w debuggee and debugger VM versions, user may still get problems. This is
+ * the case when debugger runs on 1.5.0 and debuggee runs on 1.4.2. Because JDI
+ * evolved b/w these versions (generics, enum, varargs etc.), 1.4.2 sa-jdi.jar
+ * won't implement 1.5.0 JDI properly and user would get verifier errors. This
+ * class loader solution is suited for different dot-dot release where JDI will
+ * not evolve but VM data structures might change and SA implementation might
+ * have to change. For example, a debuggee running 1.5.1 VM can be debugged
+ * with debugger running on 1.5.0 VM. Here, JDI is same but VM data structures
+ * could still change.
+ */
+
+class SAJDIClassLoader extends URLClassLoader {
+    private static final boolean DEBUG;
+    static {
+        DEBUG = System.getProperty("sun.jvm.hotspot.jdi.SAJDIClassLoader.DEBUG") != null;
+    }
+
+    private ClassLoader parent;
+    private boolean classPathSet;
+
+    SAJDIClassLoader(ClassLoader parent) {
+        super(new URL[0], parent);
+        this.parent = parent;
+    }
+
+    SAJDIClassLoader(ClassLoader parent, String classPath) {
+        this(parent);
+        this.classPathSet = true;
+        try {
+            addURL(new File(classPath).toURL());
+        } catch(MalformedURLException mue) {
+            throw new RuntimeException(mue);
+        }
+    }
+
+    public synchronized Class loadClass(String name)
+        throws ClassNotFoundException {
+        // First, check if the class has already been loaded
+        Class c = findLoadedClass(name);
+        if (c == null) {
+            /* If we are loading any class in 'sun.jvm.hotspot.'  or any of the
+             * sub-packages (except for 'debugger' sub-pkg. please refer below),
+             * we load it by 'this' loader. Or else, we forward the request to
+             * 'parent' loader, system loader etc. (rest of the code follows
+             * the patten in java.lang.ClassLoader.loadClass).
+             *
+             * 'sun.jvm.hotspot.debugger.' and sub-package classes are
+             * also loaded by parent loader. This is done for two reasons:
+             *
+             * 1. to avoid code bloat by too many classes.
+             * 2. to avoid loading same native library multiple times
+             *    from multiple class loaders (which results in getting a
+             *    UnsatisifiedLinkageError from System.loadLibrary).
+             */
+
+            if (name.startsWith("sun.jvm.hotspot.") &&
+                !name.startsWith("sun.jvm.hotspot.debugger.")) {
+                return findClass(name);
+            }
+            if (parent != null) {
+                c = parent.loadClass(name);
+            } else {
+                c = findSystemClass(name);
+            }
+        }
+        return c;
+    }
+
+    protected Class findClass(String name) throws ClassNotFoundException {
+        if (DEBUG) {
+            System.out.println("SA/JDI loader: about to load " + name);
+        }
+        if (classPathSet) {
+            return super.findClass(name);
+        } else {
+            byte[] b = null;
+            try {
+                InputStream in = getResourceAsStream(name.replace('.', '/') + ".class");
+                // Read until end of stream is reached
+                b = new byte[1024];
+                int total = 0;
+                int len = 0;
+                while ((len = in.read(b, total, b.length - total)) != -1) {
+                    total += len;
+                    if (total >= b.length) {
+                        byte[] tmp = new byte[total * 2];
+                        System.arraycopy(b, 0, tmp, 0, total);
+                        b = tmp;
+                    }
+                }
+                // Trim array to correct size, if necessary
+                if (total != b.length) {
+                    byte[] tmp = new byte[total];
+                    System.arraycopy(b, 0, tmp, 0, total);
+                    b = tmp;
+                }
+            } catch (Exception exp) {
+                throw (ClassNotFoundException) new ClassNotFoundException().initCause(exp);
+            }
+            return defineClass(name, b, 0, b.length);
+        }
+    }
+}