On 10/12/2014 04:09 AM, Claes Redestad wrote:
Taking in all these suggestions as well as realizing a race could cause different Package to return from subsequent calls to Package.defineSystemPackage brings me to this:

http://cr.openjdk.java.net/~redestad/8060130/webrev.03/


Hi Claes,

Just some nits...

- I think you're still using Map as the type of 'pkgs' and 'manifests' static fields in Package although they are CHMs at runtime.

- To avoid unnecessary (multiple) reads from a volatile field, the following code in CachedManifest:

 631         public Manifest getManifest() {
 632             resolveManifest();
 633             return manifest;
 634         }
 635
 636         private void resolveManifest() {
 637             if (manifest != null || url == null) {
 638                 return;
 639             }
 640             synchronized(this) {
 641                 if (manifest == null) {
 642                     manifest = AccessController.doPrivileged(new 
PrivilegedAction<Manifest>() {
 643                         public Manifest run() {
 644                             return loadManifest(fileName);
 645                         }
 646                     });
 647                 }
 648             }
 649         }


could be written as:

public Manifest getManifest() {
    if (url == null) return null;
    Manifest m = manifest;
    if (m != null) return m;
   synchronized (this) {
       if ((m = manifest) != null) return m;
       manifest = m = AccessControler.doPrivileged(....);
       return m;
   }
}


- It would be better to move loadManifest() into the CachedManifest class since it's only used there as a helper method (to avoid creating access bridges or having to declare it package-private instead) - well no, this doesn't help, since it's called from an anonymous inner PrivilegedAction subclass. What about just inlining it into the PrivilegeAction's run() method?

I also wonder if the lazy loading of Manifest in CachedManifest is necessary. If you look at the only usage of CachedManifest.getManifest() method (in Package.defineSystemPackage()):

        CachedManifest cachedManifest = createCachedManifest(fn);
pkgs.putIfAbsent(name, new Package(name, cachedManifest.getManifest(),
                cachedManifest.getURL()));

...you can see that getManifest() is called immediately after obtaining the CacheManifest. So there's no need for lazy loading. Loading the Manifest in CachedManifest constructor would be just fine.

Now... How about a slightly alternative approach: instead of caching Manifests we could create and cache a Package - call it a prototype - then add a private constructor taking the package name and the "prototype" Package. The Package objects should come with a smaller footprint and have the added benefit of being effectively immutable. Does that
sound like an improvement?

Or, call the prototype a 'CachedManifest' and Package just delegate methods to it. Well...

A noble goal, but this space optimization would only pertain to system packages if changed only in ClassLoader/Package. You would still have to have "fat" Packages because other ClassLoaders define their Packages with the other Package constructor that doesn't take the Manifest file name (which would be used as a key to obtain a prototype), but use their own Manifest parsing (see URLClassLoader.definePackage()) ... There are just a couple of system packages. So you would have to also change the API between individual ClassLoader(s) and ClassLoader/Package (see ClassLoader.definePackage()) to optimize other non-system packages which outnumber system packages. There are not so many packages after all (compared to Class(es)).

Regards, Peter

Reply via email to