Index: core/bootstrap/src/org/netbeans/ProxyClassLoader.java =================================================================== RCS file: /cvs/core/bootstrap/src/org/netbeans/ProxyClassLoader.java,v retrieving revision 1.2 diff -u -r1.2 ProxyClassLoader.java --- core/bootstrap/src/org/netbeans/ProxyClassLoader.java 2 Nov 2002 21:06:03 -0000 1.2 +++ core/bootstrap/src/org/netbeans/ProxyClassLoader.java 16 Dec 2002 21:45:47 -0000 @@ -112,37 +112,89 @@ } } - /** - * Loads the class with the specified name. The implementation of - * this method searches for classes in the following order:
- *
true
then resolve the class
- * @return the resulting Class
object
- * @exception ClassNotFoundException if the class could not be found
- */
- protected synchronized final Class loadClass(String name, boolean resolve)
+ protected static char[] namescratch = new char[115];
+ //needs to be big enough to accomodate
+ //org.netbeans.modules.properties.syntax.PropertiesSettingsInitializer$PropertiesTokenColoringInitializer.class
+ protected static char[] pkgscratch = new char[90];
+ //These arrays are sized > longest neede name for NetBeans -
+
+ //org.netbeans.modules.projects.CurrentProjectNode$Explorer$MiniStatusBarStateListener.class
+ private static final char[] clazzext = new char[] {'.','c','l','a','s','s'};
+ protected synchronized final Class loadClass(String name, boolean resolve)
throws ClassNotFoundException {
zombieCheck(name);
- String filename = name.replace('.', '/').concat(".class"); // NOI18N
- int idx = filename.lastIndexOf('/'); // NOI18N
- if (idx == -1) throw new ClassNotFoundException("Will not load classes from default package"); // NOI18N
- String pkg = filename.substring(0, idx + 1); // "org/netbeans/modules/foo/"
- Class c = smartLoadClass(name, filename, pkg);
+ /* The following code is an heavy optimization of
+ String filename = name.replace('.', '/').concat(".class"); // NOI18N
+ int idx = filename.lastIndexOf('/'); // NOI18N
+ to improve performance and reduce memory allocation.
+ */
+ int nlen = name.length();
+ //create an array with room for .class
+ int end = nlen +6;
+ //copy the constant char array here
+ //copy the name into the beginning of the array
+ try {
+ name.getChars(0, nlen, namescratch, 0);
+ } catch (ArrayIndexOutOfBoundsException ae1) {
+ namescratch = new char[nlen + 20];
+ name.getChars(0, nlen, namescratch, 0);
+ }
+ //quickly scan backwards and find the last occurance of '.' &
+ //save the result
+ int idx = nlen-1;
+ for (;(idx >= 0) && (namescratch[idx] != '.'); idx--) {
+ //empty impl
+ }
+ if (idx < 0) throw new ClassNotFoundException("Will not load classes from default package - " + name); // NOI18N
+ //since we know about it already, set the final . to / now
+ namescratch[idx] = '/';
+// idx++;
+
+ try {
+ //iterate forward up to package name boundary, skipping
+ //the one we already set and the preceding character (if that
+ //is / or . we have an illegal package name and it will be
+ //caught later, so doesn't matter). Overflowing doesn't matter, we
+ //will only copy up to the value of the end field, and any
+ //inadvertent modifications will be overwritten by '.class'.
+ for (int j=0; j < idx; j+=5) {
+ namescratch[j] = namescratch[j] == '.' ? '/' : namescratch[j];
+ namescratch[j+1] = namescratch[j+1] == '.' ? '/' : namescratch[j+1];
+ namescratch[j+2] = namescratch[j+2] == '.' ? '/' : namescratch[j+2];
+ namescratch[j+3] = namescratch[j+3] == '.' ? '/' : namescratch[j+3];
+ namescratch[j+4] = namescratch[j+4] == '.' ? '/' : namescratch[j+4];
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ //on the rare occasion that it won't fit, reallocate and do it again
+ char[] old = namescratch;
+ namescratch = new char[old.length + 20];
+ System.arraycopy (old, 0, namescratch, 0, old.length);
+ //do it the slow way, won't happen often if at all
+ for (int j1=0; j1 < idx; j1++) {
+ if (namescratch[j1] == '.') namescratch[j1]='/';
+ }
+ }
+
+ //now copy in the .class extension
+ try {
+ System.arraycopy(clazzext, 0, namescratch, nlen, 6);
+ } catch (ArrayIndexOutOfBoundsException ae) {
+ //on the off chance a name is too long, grow the array.
+ //Shouldn't happen often if at all
+ char[] oldscratch = namescratch;
+ namescratch = new char[end+10];
+ System.arraycopy (oldscratch, 0, namescratch, 0, oldscratch.length);
+ System.arraycopy(clazzext, 0, namescratch, nlen, 6);
+ }
+ //allocate the strings
+ String pkg = new String (namescratch,0,idx+1); // "org/netbeans/modules/foo/"
+ String fullname = new String (namescratch,0,end); // "org/netbeans/modules/foo/MyClass.class"
+ //end of string optimization
+ Class c = smartLoadClass(name, fullname, pkg);
if(c == null) throw new ClassNotFoundException(name);
if (resolve) resolveClass(c);
return c;
- }
-
+ }
/** This ClassLoader can't load anything itself. Subclasses
* may override this method to do some class loading themselves. The
* implementation should not throw any exception, just return
@@ -295,7 +347,6 @@
return super.findResources(name);
}
-
/**
* Returns a Package that has been defined by this class loader or any
* of its parents.
@@ -305,15 +356,68 @@
*/
protected Package getPackage(String name) {
zombieCheck(name);
-
+ Package pkg=null;
+ synchronized (packages) {
+ pkg=(Package) packages.get(name);
+ if (pkg != null) return pkg;
+ }
+ //below is the original code for string handling;
+ //the code in the synchronized block following
+ //accomplishes the same thing, but is optimized to
+ //reduce String array copies and is about 40% faster
+ /*
int idx = name.lastIndexOf('.');
if (idx == -1) return null;
String spkg = name.substring(0, idx + 1).replace('.', '/');
-
- synchronized (packages) {
- Package pkg = (Package)packages.get(name);
- if (pkg != null) return pkg;
-
+ */
+ String spkg;
+ int nlen = name.length();
+ //is this synchronization necessary? Probably. Works
+ //without it, but that's on a uniprocessor machine. If sure
+ //it is a non-issue, remove.
+ synchronized (pkgscratch) {
+ try {
+ //load the name into the scratch array
+ name.getChars(0, nlen-1, pkgscratch, 0);
+ } catch (ArrayIndexOutOfBoundsException ae) {
+ //if the array is too small, grow it and try again
+ pkgscratch = new char[nlen+20];
+ name.getChars(0, nlen-1, pkgscratch, 0);
+ }
+ //start at the end of the array and iterate back until
+ // a '.' is found.
+ int idx=nlen-1;
+ for (; (idx >= 0) && (pkgscratch[idx] != '.'); idx--) {
+ //empty impl-we just want the value of idx
+ }
+
+ //now iterate the array as far as necessary, replacing
+ //'.' with '/' - we'll set the last char (known) explicitly below
+ try {
+ for (int i=0; i <= idx-5; i+=4) {
+ if (pkgscratch[i] == '.') pkgscratch[i] = '/';
+ if (pkgscratch[i+1] == '.') pkgscratch[i+1] = '/';
+ if (pkgscratch[i+2] == '.') pkgscratch[i+2] = '/';
+ if (pkgscratch[i+3] == '.') pkgscratch[i+3] = '/';
+ }
+ } catch (ArrayIndexOutOfBoundsException ae2) {
+ //Faint possibility of overflowing
+ //if we need to grow the array, we've got one honkin' big package name
+ char[] oldscratch = pkgscratch;
+ pkgscratch=new char[pkgscratch.length + 20];
+ System.arraycopy (oldscratch, 0 , pkgscratch, 0, oldscratch.length);
+ for (int n = 0; n < idx; n++) {
+ if (pkgscratch[n] == '.') pkgscratch[n] = '/';
+ }
+ }
+ //if we're not in the default package, explicitly set the
+ //final trailing slash
+ if (idx >=0) pkgscratch[idx] = '/';
+ //create the result string
+ spkg = idx == -1 ? "" : new String (pkgscratch, 0, idx+1);
+ }
+ //end of optimized string loading
+ synchronized (packages) {
for (int i = 0; i < parents.length; i++) {
ClassLoader par = parents[i];
if (par instanceof ProxyClassLoader && shouldDelegateResource(spkg, par)) {