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:

- *

    - *
  1. Calls {@link #findLoadedClass(String)} to check if the class has - * already been loaded. - *
  2. Checks the caches whether another class from the same package - * was already loaded and uses the same classloader - *
  3. Tries to find the class using parent loaders in their order. - *
  4. Calls the {@link #simpleFindClass(String,String)} method to find - * the class using this class loader. - *
- * - * @param name the name of the class - * @param resolve if 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)) {