blob: b2e5dae85cb9fc42ef81a942077681ab82be3aee [file] [log] [blame]
/*
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.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).toURI().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);
}
}
}