Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-24 Thread Peter Levart


On 10/23/2014 03:27 AM, Bernd Eckenfels wrote:

Am Wed, 22 Oct 2014 14:56:59 -0700
schrieb Mandy Chung mandy.ch...@oracle.com:

I guess your question is related to my comment about two class loaders
can define classes in a package of the same name (two different
runtime packages).  ClassLoader.getPackage(s) assumes there is only
one Package for each name in the class loader chain which seems wrong
to me. Claes has filed a bug to track this:
https://bugs.openjdk.java.net/browse/JDK-8061804

Yes, I think thats the same, Mandy.

One option for solving that in a still performant (lockless on hot
path) way would be a ConcurrentSet of package names used for the
initial decision if the hierachy needs traversed (and why may define a
package). With a set of strings it would not keep the packages alive so
it can be global. Not sure if it would need a cleanup mechanism.. hmm.

Gruss
Bernd

Hi Bernd,

As it is perfectly legal for two unrelated classloaders (for example 
peers sharing common parent) to each define it's own distinct class with 
the same name (imagine two J2EE apps each using it's own version of the 
same library bundled with them), so should two unrelated classloaders be 
able to define two distinct Packages with same name - and they can do that.
Standard delegation model makes sure that a class with a particular name 
can only be defined by one classloader in the delegation chain from 
initiating to the bootstrap classloader, but not all classloaders follow 
this rule (for example WAR classloader in web containers). Packages also 
wish to follow this rule, but fail, since the existence of a package 
is established only when 1st class from that package is loaded. 
Something similar is achieved by making packages sealed, but not all 
packages are sealed, and I think that even distinct sealed packages 
with same name can exist in unrelated classloaders.
So the most consistent thing to do would be to allow each classloader to 
define it's own packages (unless ancestors define a sealed package with 
same name) and to consistently return the Package defined by the Class' 
defining classloader from the Class.getPackage() method. 
ClassLoader.getPackages() method should then return a concatenation of 
defined packages from the invoked classloader up through ancestors to 
the bootstrap classloader and this list may contain Packages with 
non-unique names.


Regards, Peter



Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-24 Thread Mandy Chung


On 10/23/2014 6:26 AM, Claes Redestad wrote:

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


Looks good.

Mandy


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-24 Thread Bernd Eckenfels
Hello Peter,

Am Fri, 24 Oct 2014 18:27:38 +0200
schrieb Peter Levart peter.lev...@gmail.com:

  One option for solving that in a still performant (lockless on hot
  path) way would be a ConcurrentSet of package names used for the
  initial decision if the hierachy needs traversed (and why may
  define a package). With a set of strings it would not keep the
  packages alive so it can be global. Not sure if it would need a
  cleanup mechanism.. hmm.

 As it is perfectly legal for two unrelated classloaders (for example 
 peers sharing common parent) to each define it's own distinct class
 with the same name (imagine two J2EE apps each using it's own version
 of the same library bundled with them), so should two unrelated
 classloaders be able to define two distinct Packages with same name -
 and they can do that.

Yes, the set is only about determine with an atomic operation if you
need to traverse the tree or not. So for the case that a package is
homed by a single class loader, that class loader will make an entry
into the set (and suceed) and then does not need to do more parent
traversal. All other class loaders will see there is already the
package name reserved, and then they will need to coordinate with their
parents.

But its just an idea after inspecting the changes, not a real analysis
of all usage models. Maybe it is enough to do it for sealed packages.

Gruss
Bernd



 Standard delegation model makes sure that a
 class with a particular name can only be defined by one classloader
 in the delegation chain from initiating to the bootstrap classloader,
 but not all classloaders follow this rule (for example WAR
 classloader in web containers). Packages also wish to follow this
 rule, but fail, since the existence of a package is established only
 when 1st class from that package is loaded. Something similar is
 achieved by making packages sealed, but not all packages are
 sealed, and I think that even distinct sealed packages with same
 name can exist in unrelated classloaders. So the most consistent
 thing to do would be to allow each classloader to define it's own
 packages (unless ancestors define a sealed package with same name)
 and to consistently return the Package defined by the Class' defining
 classloader from the Class.getPackage() method.
 ClassLoader.getPackages() method should then return a concatenation
 of defined packages from the invoked classloader up through ancestors
 to the bootstrap classloader and this list may contain Packages with
 non-unique names.
 
 Regards, Peter
 
 


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-23 Thread Claes Redestad

On 10/23/2014 02:54 AM, Mandy Chung wrote:


On 10/22/2014 4:58 PM, Claes Redestad wrote:




This test uses a special class loader that delegates to null class 
loader only.  Since you have the verification in place, it'd be good 
to also call Package.getPackage and Package.getPackages to verify 
that the same package2 instance is returned.  As a sanity check, 
you could check java.lang package must be present.


I've added some sanity checks as suggested. Sadly, it seems that 
since the application classloader will define and load package2 first 
in this test, there'll always be a Package defined in the 
ClassLoader.pkgs that will mask the Package instance in Package.pkgs 
when retrieved via the public methods in Package. 


Can you remove package2/Class2.class after you create the jar files?


Sorry for the confusion. I realized I did some of my test development on 
an unpatched JDK and got caught up in a subtle issue. Prior to the 
changes proposed, calling into Package.getSystemPackages() actually 
created new Package objects on each call(!!), breaking the assumption 
that only one Package object will ever be defined.


The proposed patch ensures we don't create new objects and that only one 
Package object can ever be created for a system package. This bug(?) was 
partially hidden by the fact that calling Package.getPackage() cached 
Package objects in the ClassLoader package maps, thus subsequent calls 
to Package.getPackages() would provide identical objects on subsequent 
calls. I've updated the test to verify Package identity (which it fails 
to do on an unpatched JDK).




If JDK-8061804 is resolved, we could change to check for identity in 
the Package.getPackages() case, which would improve the specificness 
of the test... For now, perhaps we could trick things in this test 
and put our dummy class into java.lang in our test here and ensure 
that the package retrieved is identical. Worth the hassle?


What I meant is to check if the returned Package contains java.lang 
package that always exists in the system packages. You don't need to 
put a dummy class in java.lang to get java.lang Package since it 
must be defined in the running VM. e.g. you can refactor line 169-176 
to a findPackage method that returns Package matching the given 
package name such that in line 164 you can call 
findPackage(java.lang) that should return non-null.




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

/Claes


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-22 Thread Claes Redestad

Thanks! Updated:

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

On a related note, 
java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java is 
failing when I run make TEST=jdk_lang test from jdk9-dev, and it seems 
to be due to the test expecting java.home to be set to a JRE dir inside 
a JDK. I naïvely copied my first approach from how 
sun/misc/JarIndex/JarIndexMergeForClassLoaderTest.java discovers the jar 
binary. Both these tests seems flawed and should use 
jdk.testlibrary.JDKToolFinder.getJDKTool(jar), no?


/Claes

On 10/22/2014 04:23 AM, David Holmes wrote:

Hi Claes,

In the test you should use the ProcessTools from the testlibrary not 
mess with System.getProperty(java.home) and create your own 
processes directly. The test should not require a full JDK to run, but 
should execute on a JRE or any compact profile.


Thanks,
David

On 21/10/2014 11:43 PM, Claes Redestad wrote:

Hi Mandy,

  thanks for the review!

On 10/15/2014 03:07 AM, Mandy Chung wrote:

Claes, Peter,

  Thanks for the revised webrev and Peter's thorough review. webrev.05
looks much better.  My comment is mostly minor.


ClassLoader.java

line 1582-1586 - I suggest to get rid of the oldpkg variable
(it's really the package to be used and not an old pkg).

pkg = new Package(name, specTitle, specVersion, specVendor,
implTitle, implVersion, implVendor,
sealBase, this);
if (packages.putIfAbsent(name, pkg) != null) {
throw new IllegalArgumentException(name +  already defined);
}
return pkg;

line 1634-1635: nit: the pkgName variable is not really needed.
   it's in the existing code and probably good to remove it.
   Package.java

line 473: maybe better to leave the ClassLoader parameter in the
constructor.
   I thought about adding a comment saying that this private 
constructor
   is only used for system package but keeping the loader parameter 
makes

   it more explicit.

line 569: nit: formatting - indent to the right to align the first
parameter
   to new Package(...)


Fixed.



line 621-623: is this really needed?  Uncontended case seems to be
   the common case.  It seems the synchronized overhead would be
   insignificant.


I'd prefer sticking to the double-checked idiom here, unless you insist.

I've cleaned up the code to avoid assignment in if-clauses, which
according to
anonymous sources makes the code more readable. Perhaps this addresses
some of your concerns?



line 624: a space is missing between synchronized and (


Fixed.



Looks like there is one test
jdk/test/java/lang/ClassLoader/GetPackage.java
about packages.  Can you add a new test to verify the system packages
as that
is one major change in your patch?


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

Since I don't want to add binary JAR files, I opted to add a test which
creates two JAR files,
each with a single class (with/without manifest) and then proceeds to
spawn processes
to verify that:

- when the JAR with manifest is on bootclasspath, the package can be
found via
Package.getSystemPackage and the package object reflects values added to
the manifest
- when the JAR without manifest is on bootclaspath, the package can be
found via
Package.getSystemPackage but is empty apart from name
- adding the test.classes directory to bootclasspath behaves the same as
adding the JAR
without manifest
- for any case where the class/package is not on the bootclasspath, the
package information
can not be found via Package.getSystemPackage().

Does this cover everything?

I guess there might be a way to make @run main/othervm or
main/bootclasspath pick
up a dynamically generated JAR file, but I've failed to find a way that
would make this work without
pregenerating the JARs. Suggestions on how this can be simplified are
welcome.

/Claes



Thanks
Mandy





Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-22 Thread Mandy Chung


On 10/21/2014 6:43 AM, Claes Redestad wrote:


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


Looks good.

A minor nit: Package.java line 636:   it can return EMPTY_MANIFEST that 
will set manifest to non-null so that an invalid file would avoid 
opening the file every time getManifest is called (although this case 
rarely happens).  line 639 can then be simplified.


GetSystemPackage.java test
   This is great.  Thanks for adding the test.

Can you break the long lines such as the call to JarBuilder.addClassFile 
and runSubprocess.  Have you run this on windows?  I think you need to 
use File.separator rather than / in the -Xbootclasspath/p argument.


This test uses a special class loader that delegates to null class 
loader only.  Since you have the verification in place, it'd be good to 
also call Package.getPackage and Package.getPackages to verify that the 
same package2 instance is returned.  As a sanity check, you could 
check java.lang package must be present.


In the verifyPackage, it throws Exception.  You can simply throw 
RuntimeException that would avoid the need of the checked exception.  
Nit: line 35-37, 43-46 - no need to declare these import as java.lang.* 
are imported by default.


Copyright year should be 2014.




I'd prefer sticking to the double-checked idiom here, unless you insist.

I've cleaned up the code to avoid assignment in if-clauses, which 
according to

anonymous sources makes the code more readable. Perhaps this addresses
some of your concerns?



Looks okay.  Initialize manifest to EMPTY_MANIFEST would clean that a 
little.




Since I don't want to add binary JAR files, I opted to add a test 
which creates two JAR files,
each with a single class (with/without manifest) and then proceeds to 
spawn processes

to verify that:



Thanks for adding the test.

- when the JAR with manifest is on bootclasspath, the package can be 
found via
Package.getSystemPackage and the package object reflects values added 
to the manifest
- when the JAR without manifest is on bootclaspath, the package can be 
found via

Package.getSystemPackage but is empty apart from name
- adding the test.classes directory to bootclasspath behaves the same 
as adding the JAR

without manifest
- for any case where the class/package is not on the bootclasspath, 
the package information

can not be found via Package.getSystemPackage().

Does this cover everything?



This is great.   See my comment above.

I guess there might be a way to make @run main/othervm or 
main/bootclasspath pick
up a dynamically generated JAR file, but I've failed to find a way 
that would make this work without
pregenerating the JARs. Suggestions on how this can be simplified are 
welcome.




What you have is fine.   The other way is to do it in a shell test that 
is not preferable as you would have to manage FS for different OSes etc.


Mandy



Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-22 Thread Mandy Chung


On 10/21/2014 2:08 PM, Bernd Eckenfels wrote:

Hello,

one thing I wonder - in the old and in the new case there is nothing
in definePackage() guaring the parents from getting to know the new
package and causing a conflict (as the atomic insert is only on the
specific packages table. Are those (parent and system package)
immutable?



Each class loader maintains its own package map.

I guess your question is related to my comment about two class loaders
can define classes in a package of the same name (two different runtime
packages).  ClassLoader.getPackage(s) assumes there is only one Package
for each name in the class loader chain which seems wrong to me. Claes
has filed a bug to track this:
  https://bugs.openjdk.java.net/browse/JDK-8061804

Mandy
[1] 
http://mail.openjdk.java.net/pipermail/core-libs-dev/2014-October/029146.html



Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-22 Thread Claes Redestad


On 2014-10-22 23:35, Mandy Chung wrote:


On 10/21/2014 6:43 AM, Claes Redestad wrote:


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


Looks good.


Thanks!



A minor nit: Package.java line 636:   it can return EMPTY_MANIFEST 
that will set manifest to non-null so that an invalid file would avoid 
opening the file every time getManifest is called (although this case 
rarely happens).  line 639 can then be simplified.


We need to consider the case where JarInputStream.getManifest() returns 
null, which would mean we'd either end up no simpler on line 639 or 
simply adding a similar check around the value returned from 
jis.getManifest(). I also think I saw that referencing the static 
EMPTY_PACKAGES from within the privileged anonymous class adds synthetic 
access methods...


More importantly, the current approach should already ensure any file is 
only scanned once by virtue of always setting manifest to a non-null 
value in the end. No?




GetSystemPackage.java test
   This is great.  Thanks for adding the test.


Thanks!



Can you break the long lines such as the call to 
JarBuilder.addClassFile and runSubprocess. 


Sure. Cleaned it up a bit.

Have you run this on windows?  I think you need to use File.separator 
rather than / in the -Xbootclasspath/p argument.


Yes, I've run the test via JPRT and verified it gets picked up and run 
using the default testset, so Windows, Solaris, Mac and Linux should be 
covered.




This test uses a special class loader that delegates to null class 
loader only.  Since you have the verification in place, it'd be good 
to also call Package.getPackage and Package.getPackages to verify that 
the same package2 instance is returned.  As a sanity check, you 
could check java.lang package must be present.


I've added some sanity checks as suggested. Sadly, it seems that since 
the application classloader will define and load package2 first in this 
test, there'll always be a Package defined in the ClassLoader.pkgs that 
will mask the Package instance in Package.pkgs when retrieved via the 
public methods in Package. If JDK-8061804 is resolved, we could change 
to check for identity in the Package.getPackages() case, which would 
improve the specificness of the test... For now, perhaps we could trick 
things in this test and put our dummy class into java.lang in our test 
here and ensure that the package retrieved is identical. Worth the hassle?




In the verifyPackage, it throws Exception.  You can simply throw 
RuntimeException that would avoid the need of the checked exception. 


Sure. I've restructured a bit to keep line lengths in check.

Nit: line 35-37, 43-46 - no need to declare these import as 
java.lang.* are imported by default.


Some IDEs...



Copyright year should be 2014.


Fixed.

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

/Claes






I'd prefer sticking to the double-checked idiom here, unless you insist.

I've cleaned up the code to avoid assignment in if-clauses, which 
according to

anonymous sources makes the code more readable. Perhaps this addresses
some of your concerns?



Looks okay.  Initialize manifest to EMPTY_MANIFEST would clean that a 
little.




Since I don't want to add binary JAR files, I opted to add a test 
which creates two JAR files,
each with a single class (with/without manifest) and then proceeds to 
spawn processes

to verify that:



Thanks for adding the test.

- when the JAR with manifest is on bootclasspath, the package can be 
found via
Package.getSystemPackage and the package object reflects values added 
to the manifest
- when the JAR without manifest is on bootclaspath, the package can 
be found via

Package.getSystemPackage but is empty apart from name
- adding the test.classes directory to bootclasspath behaves the same 
as adding the JAR

without manifest
- for any case where the class/package is not on the bootclasspath, 
the package information

can not be found via Package.getSystemPackage().

Does this cover everything?



This is great.   See my comment above.

I guess there might be a way to make @run main/othervm or 
main/bootclasspath pick
up a dynamically generated JAR file, but I've failed to find a way 
that would make this work without
pregenerating the JARs. Suggestions on how this can be simplified are 
welcome.




What you have is fine.   The other way is to do it in a shell test 
that is not preferable as you would have to manage FS for different 
OSes etc.


Mandy





Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-22 Thread Mandy Chung


On 10/22/2014 4:58 PM, Claes Redestad wrote:




A minor nit: Package.java line 636:   it can return EMPTY_MANIFEST 
that will set manifest to non-null so that an invalid file would 
avoid opening the file every time getManifest is called (although 
this case rarely happens).  line 639 can then be simplified.


We need to consider the case where JarInputStream.getManifest() 
returns null, which would mean we'd either end up no simpler on line 
639 or simply adding a similar check around the value returned from 
jis.getManifest(). I also think I saw that referencing the static 
EMPTY_PACKAGES from within the privileged anonymous class adds 
synthetic access methods...


More importantly, the current approach should already ensure any file 
is only scanned once by virtue of always setting manifest to a 
non-null value in the end. No?


That's right.  I missed that you did set manifest to non-null in line 
639.  That's fine then.



Yes, I've run the test via JPRT and verified it gets picked up and run 
using the default testset, so Windows, Solaris, Mac and Linux should 
be covered.


That's good.





This test uses a special class loader that delegates to null class 
loader only.  Since you have the verification in place, it'd be good 
to also call Package.getPackage and Package.getPackages to verify 
that the same package2 instance is returned.  As a sanity check, 
you could check java.lang package must be present.


I've added some sanity checks as suggested. Sadly, it seems that since 
the application classloader will define and load package2 first in 
this test, there'll always be a Package defined in the 
ClassLoader.pkgs that will mask the Package instance in Package.pkgs 
when retrieved via the public methods in Package. 


Can you remove package2/Class2.class after you create the jar files?

If JDK-8061804 is resolved, we could change to check for identity in 
the Package.getPackages() case, which would improve the specificness 
of the test... For now, perhaps we could trick things in this test and 
put our dummy class into java.lang in our test here and ensure that 
the package retrieved is identical. Worth the hassle?


What I meant is to check if the returned Package contains java.lang 
package that always exists in the system packages.  You don't need to 
put a dummy class in java.lang to get java.lang Package since it must 
be defined in the running VM.  e.g. you can refactor line 169-176 to a 
findPackage method that returns Package matching the given package name 
such that in line 164 you can call findPackage(java.lang) that should 
return non-null.





Nit: line 35-37, 43-46 - no need to declare these import as 
java.lang.* are imported by default.


Some IDEs...



Which IDE are you using?  I think it might be your configuration.

Thanks
Mandy


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-22 Thread Bernd Eckenfels
Am Wed, 22 Oct 2014 14:56:59 -0700
schrieb Mandy Chung mandy.ch...@oracle.com:
 I guess your question is related to my comment about two class loaders
 can define classes in a package of the same name (two different
 runtime packages).  ClassLoader.getPackage(s) assumes there is only
 one Package for each name in the class loader chain which seems wrong
 to me. Claes has filed a bug to track this:
https://bugs.openjdk.java.net/browse/JDK-8061804

Yes, I think thats the same, Mandy.

One option for solving that in a still performant (lockless on hot
path) way would be a ConcurrentSet of package names used for the
initial decision if the hierachy needs traversed (and why may define a
package). With a set of strings it would not keep the packages alive so
it can be global. Not sure if it would need a cleanup mechanism.. hmm.

Gruss
Bernd


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-22 Thread David Holmes

On 22/10/2014 10:40 PM, Claes Redestad wrote:

Thanks! Updated:

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

On a related note,
java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java is
failing when I run make TEST=jdk_lang test from jdk9-dev, and it seems
to be due to the test expecting java.home to be set to a JRE dir inside
a JDK. I naïvely copied my first approach from how
sun/misc/JarIndex/JarIndexMergeForClassLoaderTest.java discovers the jar
binary. Both these tests seems flawed and should use
jdk.testlibrary.JDKToolFinder.getJDKTool(jar), no?


Yes. :) They should just use the available jar tool (normally from the 
compile JDK).


Thanks,
David


/Claes

On 10/22/2014 04:23 AM, David Holmes wrote:

Hi Claes,

In the test you should use the ProcessTools from the testlibrary not
mess with System.getProperty(java.home) and create your own
processes directly. The test should not require a full JDK to run, but
should execute on a JRE or any compact profile.

Thanks,
David

On 21/10/2014 11:43 PM, Claes Redestad wrote:

Hi Mandy,

  thanks for the review!

On 10/15/2014 03:07 AM, Mandy Chung wrote:

Claes, Peter,

  Thanks for the revised webrev and Peter's thorough review. webrev.05
looks much better.  My comment is mostly minor.


ClassLoader.java

line 1582-1586 - I suggest to get rid of the oldpkg variable
(it's really the package to be used and not an old pkg).

pkg = new Package(name, specTitle, specVersion, specVendor,
implTitle, implVersion, implVendor,
sealBase, this);
if (packages.putIfAbsent(name, pkg) != null) {
throw new IllegalArgumentException(name +  already defined);
}
return pkg;

line 1634-1635: nit: the pkgName variable is not really needed.
   it's in the existing code and probably good to remove it.
   Package.java

line 473: maybe better to leave the ClassLoader parameter in the
constructor.
   I thought about adding a comment saying that this private
constructor
   is only used for system package but keeping the loader parameter
makes
   it more explicit.

line 569: nit: formatting - indent to the right to align the first
parameter
   to new Package(...)


Fixed.



line 621-623: is this really needed?  Uncontended case seems to be
   the common case.  It seems the synchronized overhead would be
   insignificant.


I'd prefer sticking to the double-checked idiom here, unless you insist.

I've cleaned up the code to avoid assignment in if-clauses, which
according to
anonymous sources makes the code more readable. Perhaps this addresses
some of your concerns?



line 624: a space is missing between synchronized and (


Fixed.



Looks like there is one test
jdk/test/java/lang/ClassLoader/GetPackage.java
about packages.  Can you add a new test to verify the system packages
as that
is one major change in your patch?


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

Since I don't want to add binary JAR files, I opted to add a test which
creates two JAR files,
each with a single class (with/without manifest) and then proceeds to
spawn processes
to verify that:

- when the JAR with manifest is on bootclasspath, the package can be
found via
Package.getSystemPackage and the package object reflects values added to
the manifest
- when the JAR without manifest is on bootclaspath, the package can be
found via
Package.getSystemPackage but is empty apart from name
- adding the test.classes directory to bootclasspath behaves the same as
adding the JAR
without manifest
- for any case where the class/package is not on the bootclasspath, the
package information
can not be found via Package.getSystemPackage().

Does this cover everything?

I guess there might be a way to make @run main/othervm or
main/bootclasspath pick
up a dynamically generated JAR file, but I've failed to find a way that
would make this work without
pregenerating the JARs. Suggestions on how this can be simplified are
welcome.

/Claes



Thanks
Mandy





Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-21 Thread Claes Redestad

Hi Mandy,

 thanks for the review!

On 10/15/2014 03:07 AM, Mandy Chung wrote:

Claes, Peter,

  Thanks for the revised webrev and Peter's thorough review. webrev.05
looks much better.  My comment is mostly minor.


ClassLoader.java

line 1582-1586 - I suggest to get rid of the oldpkg variable
(it's really the package to be used and not an old pkg).

pkg = new Package(name, specTitle, specVersion, specVendor,
implTitle, implVersion, implVendor,
sealBase, this);
if (packages.putIfAbsent(name, pkg) != null) {
throw new IllegalArgumentException(name +  already defined);
}
return pkg;

line 1634-1635: nit: the pkgName variable is not really needed.
   it's in the existing code and probably good to remove it.
   Package.java

line 473: maybe better to leave the ClassLoader parameter in the 
constructor.

   I thought about adding a comment saying that this private constructor
   is only used for system package but keeping the loader parameter makes
   it more explicit.

line 569: nit: formatting - indent to the right to align the first 
parameter

   to new Package(...)


Fixed.



line 621-623: is this really needed?  Uncontended case seems to be
   the common case.  It seems the synchronized overhead would be
   insignificant.


I'd prefer sticking to the double-checked idiom here, unless you insist.

I've cleaned up the code to avoid assignment in if-clauses, which 
according to

anonymous sources makes the code more readable. Perhaps this addresses
some of your concerns?



line 624: a space is missing between synchronized and (


Fixed.



Looks like there is one test 
jdk/test/java/lang/ClassLoader/GetPackage.java
about packages.  Can you add a new test to verify the system packages 
as that

is one major change in your patch?


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

Since I don't want to add binary JAR files, I opted to add a test which 
creates two JAR files,
each with a single class (with/without manifest) and then proceeds to 
spawn processes

to verify that:

- when the JAR with manifest is on bootclasspath, the package can be 
found via
Package.getSystemPackage and the package object reflects values added to 
the manifest
- when the JAR without manifest is on bootclaspath, the package can be 
found via

Package.getSystemPackage but is empty apart from name
- adding the test.classes directory to bootclasspath behaves the same as 
adding the JAR

without manifest
- for any case where the class/package is not on the bootclasspath, the 
package information

can not be found via Package.getSystemPackage().

Does this cover everything?

I guess there might be a way to make @run main/othervm or 
main/bootclasspath pick
up a dynamically generated JAR file, but I've failed to find a way that 
would make this work without
pregenerating the JARs. Suggestions on how this can be simplified are 
welcome.


/Claes



Thanks
Mandy



Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-21 Thread Bernd Eckenfels
Hello,

one thing I wonder - in the old and in the new case there is nothing
in definePackage() guaring the parents from getting to know the new
package and causing a conflict (as the atomic insert is only on the
specific packages table. Are those (parent and system package)
immutable?

Gruss
Bernd

the package  Am Tue, 21 Oct 2014 15:43:07
+0200 schrieb Claes Redestad claes.redes...@oracle.com:

 Hi Mandy,
 
   thanks for the review!
 
 On 10/15/2014 03:07 AM, Mandy Chung wrote:
  Claes, Peter,
 
Thanks for the revised webrev and Peter's thorough review.
  webrev.05 looks much better.  My comment is mostly minor.
 
 
  ClassLoader.java
 
  line 1582-1586 - I suggest to get rid of the oldpkg variable
  (it's really the package to be used and not an old pkg).
 
  pkg = new Package(name, specTitle, specVersion, specVendor,
  implTitle, implVersion, implVendor,
  sealBase, this);
  if (packages.putIfAbsent(name, pkg) != null) {
  throw new IllegalArgumentException(name +  already
  defined); }
  return pkg;
 
  line 1634-1635: nit: the pkgName variable is not really needed.
 it's in the existing code and probably good to remove it.
 Package.java
 
  line 473: maybe better to leave the ClassLoader parameter in the 
  constructor.
 I thought about adding a comment saying that this private
  constructor is only used for system package but keeping the loader
  parameter makes it more explicit.
 
  line 569: nit: formatting - indent to the right to align the first 
  parameter
 to new Package(...)
 
 Fixed.
 
 
  line 621-623: is this really needed?  Uncontended case seems to be
 the common case.  It seems the synchronized overhead would be
 insignificant.
 
 I'd prefer sticking to the double-checked idiom here, unless you
 insist.
 
 I've cleaned up the code to avoid assignment in if-clauses, which 
 according to
 anonymous sources makes the code more readable. Perhaps this addresses
 some of your concerns?
 
 
  line 624: a space is missing between synchronized and (
 
 Fixed.
 
 
  Looks like there is one test 
  jdk/test/java/lang/ClassLoader/GetPackage.java
  about packages.  Can you add a new test to verify the system
  packages as that
  is one major change in your patch?
 
 http://cr.openjdk.java.net/~redestad/8060130/webrev.06
 
 Since I don't want to add binary JAR files, I opted to add a test
 which creates two JAR files,
 each with a single class (with/without manifest) and then proceeds to 
 spawn processes
 to verify that:
 
 - when the JAR with manifest is on bootclasspath, the package can be 
 found via
 Package.getSystemPackage and the package object reflects values added
 to the manifest
 - when the JAR without manifest is on bootclaspath, the package can
 be found via
 Package.getSystemPackage but is empty apart from name
 - adding the test.classes directory to bootclasspath behaves the same
 as adding the JAR
 without manifest
 - for any case where the class/package is not on the bootclasspath,
 the package information
 can not be found via Package.getSystemPackage().
 
 Does this cover everything?
 
 I guess there might be a way to make @run main/othervm or 
 main/bootclasspath pick
 up a dynamically generated JAR file, but I've failed to find a way
 that would make this work without
 pregenerating the JARs. Suggestions on how this can be simplified are 
 welcome.
 
 /Claes
 
 
  Thanks
  Mandy
 



Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-15 Thread David M. Lloyd

On 10/14/2014 07:22 PM, Mandy Chung wrote:


On 10/13/2014 5:50 AM, David M. Lloyd wrote:

On 10/10/2014 07:31 PM, Mandy Chung wrote:


On 10/10/2014 8:10 AM, Claes Redestad wrote:

Hi all,

please review this patch which attempts to clean up synchronization
and improve scalability when
defining and getting java.lang.Package objects.


I agree with David that getting Package objects are not performance
critical. On the other hand, the code defining/getting Packages is
old and deserves some cleanup especially the synchronization part.


I have a little more information on this subject.  We've a possible
(and somewhat likely) deadlock which occurs because one thread can
attempt to define a system class while holding the
java.lang.Package#pkgs lock, while another thread can attempt to get a
package while defining a system class (while holding the class loader
lock).  I do not recall whether parallel class loading alleviates this
issue.  We solved the problem by loading Packages.getPackages() in
early (single-threaded) bootstrap.



Do you recall what JDK version you observed this possible deadlock? I
wonder if the fix for 7001933 [1] in JDK 7 and 6u25 resolved the
deadlock problem you ran into.

[1] http://hg.openjdk.java.net/jdk9/dev/jdk/rev/4a7da412db38


The change would have been observed in early 2011 so I think it was 
probably a JDK 6 version before 25 (which I did not install until April 
of that year) - looks like most likely candidate based on my JDK 
directory is 1.6.0_22.



So from my perspective, just getting rid of the synchronization on
that field alone makes this change worthwhile.


Yes that's what I think too.

Mandy


--
- DML


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-15 Thread Mandy Chung


On 10/15/2014 5:43 AM, David M. Lloyd wrote:

On 10/14/2014 07:22 PM, Mandy Chung wrote:


On 10/13/2014 5:50 AM, David M. Lloyd wrote:


I have a little more information on this subject.  We've a possible
(and somewhat likely) deadlock which occurs because one thread can
attempt to define a system class while holding the
java.lang.Package#pkgs lock, while another thread can attempt to get a
package while defining a system class (while holding the class loader
lock).  I do not recall whether parallel class loading alleviates this
issue.  We solved the problem by loading Packages.getPackages() in
early (single-threaded) bootstrap.



Do you recall what JDK version you observed this possible deadlock? I
wonder if the fix for 7001933 [1] in JDK 7 and 6u25 resolved the
deadlock problem you ran into.

[1] http://hg.openjdk.java.net/jdk9/dev/jdk/rev/4a7da412db38


The change would have been observed in early 2011 so I think it was 
probably a JDK 6 version before 25 (which I did not install until 
April of that year) - looks like most likely candidate based on my JDK 
directory is 1.6.0_22.




Thanks.  It's possible that it's the same deadlock issue.

Mandy


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-14 Thread Mandy Chung


On 10/13/2014 5:50 AM, David M. Lloyd wrote:

On 10/10/2014 07:31 PM, Mandy Chung wrote:


On 10/10/2014 8:10 AM, Claes Redestad wrote:

Hi all,

please review this patch which attempts to clean up synchronization
and improve scalability when
defining and getting java.lang.Package objects.


I agree with David that getting Package objects are not performance
critical. On the other hand, the code defining/getting Packages is
old and deserves some cleanup especially the synchronization part.


I have a little more information on this subject.  We've a possible 
(and somewhat likely) deadlock which occurs because one thread can 
attempt to define a system class while holding the 
java.lang.Package#pkgs lock, while another thread can attempt to get a 
package while defining a system class (while holding the class loader 
lock).  I do not recall whether parallel class loading alleviates this 
issue.  We solved the problem by loading Packages.getPackages() in 
early (single-threaded) bootstrap.




Do you recall what JDK version you observed this possible deadlock? I 
wonder if the fix for 7001933 [1] in JDK 7 and 6u25 resolved the 
deadlock problem you ran into.


[1] http://hg.openjdk.java.net/jdk9/dev/jdk/rev/4a7da412db38

So from my perspective, just getting rid of the synchronization on 
that field alone makes this change worthwhile.


Yes that's what I think too.

Mandy


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-14 Thread Mandy Chung

Claes, Peter,

  Thanks for the revised webrev and Peter's thorough review.  webrev.05
looks much better.  My comment is mostly minor.

On 10/13/2014 8:41 AM, Claes Redestad wrote:

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


ClassLoader.java

line 1582-1586 - I suggest to get rid of the oldpkg variable
(it's really the package to be used and not an old pkg).

pkg = new Package(name, specTitle, specVersion, specVendor,
implTitle, implVersion, implVendor,
sealBase, this);
if (packages.putIfAbsent(name, pkg) != null) {
throw new IllegalArgumentException(name +  already defined);
}
return pkg;

line 1634-1635: nit: the pkgName variable is not really needed.
   it's in the existing code and probably good to remove it.
   
Package.java


line 473: maybe better to leave the ClassLoader parameter in the constructor.
   I thought about adding a comment saying that this private constructor
   is only used for system package but keeping the loader parameter makes
   it more explicit.

line 569: nit: formatting - indent to the right to align the first parameter
   to new Package(...)

line 621-623: is this really needed?  Uncontended case seems to be
   the common case.  It seems the synchronized overhead would be
   insignificant.

line 624: a space is missing between synchronized and (

Looks like there is one test jdk/test/java/lang/ClassLoader/GetPackage.java
about packages.  Can you add a new test to verify the system packages as that
is one major change in your patch?

Thanks
Mandy



Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-14 Thread Mandy Chung


On 10/13/2014 2:04 AM, Peter Levart wrote:

On 10/13/2014 04:18 AM, David Holmes wrote:


Looking at definePackage it seems both old and new code have serious 
race conditions due to a lack of atomicity when checking the 
parent/system packages. A package of the same name could be defined 
in the parent/system after definePackage has called getPackage - and 
we then end up with two same named Packages in different loaders.




I don't know the history of the getPackage(s) methods. Since two 
different class loaders can define a package of the same name and 
effectively two separate runtime packages, it seems to me that 
ClassLoader.getPackages should return all Package objects including the 
duplicated names.  Claes - do you mind filing a bug for it?



...
p1: package javax.swing
p2: package javax.swing, Java Platform API Specification, version 1.9
p3: package javax.swing, Java Platform API Specification, version 1.9


Now if the order of class loading is changed:

...
p1: package javax.swing, Java Platform API Specification, version 1.9
p2: package javax.swing, Java Platform API Specification, version 1.9
p3: package javax.swing, Java Platform API Specification, version 1.9


So reliable sealed packages can only exist if they are defined 
in-advance or at least one class from a particular sealed package is 
loaded by the authoritative ClassLoader before a child of that loader 
is given a chance to load classes.


A: So perhaps, to support class-loading-order independent behaviour, a 
descendant ClassLoader could be given a chance to define it's own 
package although the ancestor has already defined one with the same 
name, unless this is a sealed package of course.


B: A backwards-incompatible and more restrictive strategy could be to 
prevent an ancestor ClassLoader from defining a Package if one of 
descendants in the chain leading  from initiating ClassLoader to the 
ancestor already defines a package with the same name. This would not 
prevent loading of such conflicting classes for the entire system, 
but only for a particular code that happens to be defined by the 
ClassLoader that (or it's ancestor) violates the constraint that a 
descendant ClassLoader must not define classes in the package of the 
same name as ancestor ClassLoader. It would prevent classes loaded by 
a violating ClassLoader from accessing classes in sealed packages, 
which might be enough to enforce intra-package access restrictions...


How does Jigsaw solve this puzzle?


java.lang.Package is not used at runtime.  I think 
ClassLoader.getPackage(s) method should be revisited whether it should 
lookup its parent loader.   I think your question concerns the runtime 
package that is not effect by java.lang.Package.


Mandy


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-13 Thread Peter Levart

On 10/13/2014 04:18 AM, David Holmes wrote:

Hi Claes,

Looking at version three ...

You seemed to have changed the caching strategy for Packages in the 
classloader. Previously a Package defined by a parent or the system 
would be updated in the current loader's Package map; but now you 
leave them separate so future lookups will always have to traverse the 
hierarchy. This doesn't seem like a performance gain.


Looking at definePackage it seems both old and new code have serious 
race conditions due to a lack of atomicity when checking the 
parent/system packages. A package of the same name could be defined in 
the parent/system after definePackage has called getPackage - and we 
then end up with two same named Packages in different loaders.


Hmm...

It's hard to come up with a consistent behaviour which would prevent 
parent / child ClassLoaders from defining classes in the same package. 
You can't prevent child prom defining a package before you know that 
parent has a package with the same name and you cant prevent a parent 
from defining a package if child has already defined a package with the 
same name. Packages are rarely backed by a resource which could be used 
to identify their existence. It's odd that the package that is returned 
from Class.getPackage() depends on the order of class loading.


For example, if user code declares a public class javax.swing.JNotSwing 
{}, then the following program:


public class Test {

public static void main(String[] args) {

JNotSwing c1 = new JNotSwing();
Package p1 = c1.getClass().getPackage();

JComponent c2 = new JLabel();
Package p2 = c2.getClass().getPackage();

JComponent c3 = new JPanel();
Package p3 = c3.getClass().getPackage();

System.out.println(p1:  + p1);
System.out.println(p2:  + p2);
System.out.println(p3:  + p3);
}
}


Prints:

p1: package javax.swing
p2: package javax.swing, Java Platform API Specification, version 1.9
p3: package javax.swing, Java Platform API Specification, version 1.9


Now if the order of class loading is changed:

public class Test {

public static void main(String[] args) {

JComponent c2 = new JLabel();
Package p2 = c2.getClass().getPackage();

JNotSwing c1 = new JNotSwing();
Package p1 = c1.getClass().getPackage();

JComponent c3 = new JPanel();
Package p3 = c3.getClass().getPackage();

System.out.println(p1:  + p1);
System.out.println(p2:  + p2);
System.out.println(p3:  + p3);
}
}


The following is printed:

p1: package javax.swing, Java Platform API Specification, version 1.9
p2: package javax.swing, Java Platform API Specification, version 1.9
p3: package javax.swing, Java Platform API Specification, version 1.9


So reliable sealed packages can only exist if they are defined 
in-advance or at least one class from a particular sealed package is 
loaded by the authoritative ClassLoader before a child of that loader is 
given a chance to load classes.


A: So perhaps, to support class-loading-order independent behaviour, a 
descendant ClassLoader could be given a chance to define it's own 
package although the ancestor has already defined one with the same 
name, unless this is a sealed package of course.


B: A backwards-incompatible and more restrictive strategy could be to 
prevent an ancestor ClassLoader from defining a Package if one of 
descendants in the chain leading  from initiating ClassLoader to the 
ancestor already defines a package with the same name. This would not 
prevent loading of such conflicting classes for the entire system, but 
only for a particular code that happens to be defined by the ClassLoader 
that (or it's ancestor) violates the constraint that a descendant 
ClassLoader must not define classes in the package of the same name as 
ancestor ClassLoader. It would prevent classes loaded by a violating 
ClassLoader from accessing classes in sealed packages, which might be 
enough to enforce intra-package access restrictions...


How does Jigsaw solve this puzzle?

Regards, Peter



No comment on the manifest caching aspect - I'm not familiar enough 
with the existing code.


On 12/10/2014 12:09 PM, Claes Redestad wrote:

On 2014-10-11 02:31, Mandy Chung wrote:


On 10/10/2014 8:10 AM, Claes Redestad wrote:

Hi all,

please review this patch which attempts to clean up synchronization
and improve scalability when
defining and getting java.lang.Package objects.


I agree with David that getting Package objects are not performance
critical. On the other hand, the code defining/getting Packages is
old and deserves some cleanup especially the synchronization part.

If you run helloworld program, how does that change the list of loaded
classes besides the new CachedManifest class?



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


ClassLoader.java
line 272: can you change the declared type as Map.


Map misses the 

Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-13 Thread David M. Lloyd

On 10/10/2014 07:31 PM, Mandy Chung wrote:


On 10/10/2014 8:10 AM, Claes Redestad wrote:

Hi all,

please review this patch which attempts to clean up synchronization
and improve scalability when
defining and getting java.lang.Package objects.


I agree with David that getting Package objects are not performance
critical. On the other hand, the code defining/getting Packages is
old and deserves some cleanup especially the synchronization part.


I have a little more information on this subject.  We've a possible (and 
somewhat likely) deadlock which occurs because one thread can attempt to 
define a system class while holding the java.lang.Package#pkgs lock, 
while another thread can attempt to get a package while defining a 
system class (while holding the class loader lock).  I do not recall 
whether parallel class loading alleviates this issue.  We solved the 
problem by loading Packages.getPackages() in early (single-threaded) 
bootstrap.


So from my perspective, just getting rid of the synchronization on that 
field alone makes this change worthwhile.

--
- DML


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-13 Thread Claes Redestad

On 10/13/2014 04:18 AM, David Holmes wrote:

Hi Claes,

Looking at version three ...

You seemed to have changed the caching strategy for Packages in the 
classloader. Previously a Package defined by a parent or the system 
would be updated in the current loader's Package map; but now you 
leave them separate so future lookups will always have to traverse the 
hierarchy. This doesn't seem like a performance gain.


Right, this would be a throughput-footprint tradeoff: adding more CHM 
entries versus taking a small penalty for having to potentially look 
things up in all the ancestral classloaders + Packages.pkgs.


I believe the caching was put in place mostly to avoid a chain of 
relatively expensive synchronization locks with potential for deadlocks, 
not to solve an actual throughput problem in uncontended cases. There 
might be a break-off somewhere due to chaining classloaders, but I've 
not been able to construct a benchmark where this is the case. I could 
swing either way on this, but with a trivial lookup cost even in the 
worst case I generally think we should favor footprint here and defer 
caching-for-performance to the application if ever necessary.




Looking at definePackage it seems both old and new code have serious 
race conditions due to a lack of atomicity when checking the 
parent/system packages. A package of the same name could be defined in 
the parent/system after definePackage has called getPackage - and we 
then end up with two same named Packages in different loaders.


Very interesting, but since we're not changing behavior and the issue of 
classloading order Peter points out can't be resolved by adding 
atomicity guarantees, I feel this is out of scope for this cleanup. 
Should we file a new bug to examine this?


/Claes



No comment on the manifest caching aspect - I'm not familiar enough 
with the existing code.


On 12/10/2014 12:09 PM, Claes Redestad wrote:

On 2014-10-11 02:31, Mandy Chung wrote:


On 10/10/2014 8:10 AM, Claes Redestad wrote:

Hi all,

please review this patch which attempts to clean up synchronization
and improve scalability when
defining and getting java.lang.Package objects.


I agree with David that getting Package objects are not performance
critical. On the other hand, the code defining/getting Packages is
old and deserves some cleanup especially the synchronization part.

If you run helloworld program, how does that change the list of loaded
classes besides the new CachedManifest class?



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


ClassLoader.java
line 272: can you change the declared type as Map.


Map misses the atomicity requirement of putIfAbsent, ConcurrentMap is OK
but leaves some
related questions open (why we can't add a null value, specifically).
I'm glad it was brought up
and discussed and will use ConcurrentHashMap for private fields unless
there's a strong
preference otherwise.



definePackage throws IAE if there exists an existing package either
in this class loader or one of its ancestors.
  - this change would not catch if two definePackage calls to define
  a package of the same name but with different spec version, title, 
etc

  concurrently.

  You may not be able to avoid synchronizing on packages for this case.


Right, I was I think synchronization can still be avoided by throwing
IAE if
putIfAbsent doesn't return null:

 if (packages.putIfAbsent(name, pkg) != null) {
 throw new IllegalArgumentException(name);
 }
 return pkg;



move line 1623 to 1630 so that the declaration of map is closer to
the assignment.


Ok



Package.java

line 557 there is a possibility that new Package[pkgs.size()] is not
big enough and a new array would be created.  As this method is not
popularly used, it's okay if another array is created.


Yes, an unlikely race.



line 563 and 565 can be merged

line 570-575: do you think you can modify the private
  Package(String name, Manifest man, URL url, ClassLoader loader)
constructor
to take null Manifest and null url so that these lines can be folded 
into


pkg = new Package(name,  cachedManifest.getManifest(),
cachedManifest.getURL(), null);


I think I'll take your suggestion below and ensure cachedManifest and
it's getManifest()
never evaluate to null, which makes for a cleaner patch. There is some
code duplication
here with URLClassLoader#definePackage. Future cleanup?

It would seem the ClassLoader argument in this ctor is always called
with null. Remove?



I think CachedManifest class and the createCachedManifest method need
some work.  Perhaps we can have the CachedManifest constructor to
obtain the URL.

Each invalid fn will have one instance instead of NO_MANIFEST singleton
but that should not happen as fn is the filename where the classes
loaded from the bootclasspath.  CachedManifest.url can then become 
final.


line 587-601 would not be needed. Can we avoid line 606 and write
the createCachedManifest method this way:
   

Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-13 Thread Peter Levart

Hi Claes,

Regarding CachedManifest I have one more comment. It's usually better to 
use null/zero as uninitialized state for lazy-initialized fields. You 
spare one (volatile) write and don't worry about unsafe publication 
which might see the Java-default value instead of the one assigned in 
initializer as uninitialized. So summing-up all comments from previous 
mails I would write CachedManifest class as:


private static class CachedManifest {
static final Manifest NO_MANIFEST = new Manifest();
final String fileName;
private final URL url;
private volatile Manifest manifest;

CachedManifest(final String fileName) {
this.fileName = fileName;
this.url = AccessController.doPrivileged(new 
PrivilegedActionURL() {

public URL run() {
final File file = new File(fileName);
if (file.isFile()) {
try {
return ParseUtil.fileToEncodedURL(file);
} catch (MalformedURLException e) {
}
}
return null;
}
});
}

public URL getURL() {
return url;
}

public Manifest getManifest() {
if (url == null) return null;
Manifest m = manifest;
if (m == null) {
synchronized (this) {
if ((m = manifest) == null) {
manifest = m = 
AccessController.doPrivileged(new PrivilegedActionManifest() {

public Manifest run() {
try (FileInputStream fis = new 
FileInputStream(fileName);
 JarInputStream jis = new 
JarInputStream(fis, false))

{
return jis.getManifest();
} catch (IOException e) {
return NO_MANIFEST;
}
}
});
}
}
}
return (m == NO_MANIFEST) ? null : m;
}
}


What do you say?

Regards, Peter


On 10/13/2014 04:32 PM, Peter Levart wrote:

On 10/12/2014 04:09 AM, Claes Redestad wrote:



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



Hi Claes,

First, one more nit:

1635 if (!map.containsKey(pkgName)) {
1636 map.put(pkgName, pkg);
1637 }

..could be written as:

map.putIfAbsent(pkgName, pkg);



And second, I re-read the code of CachedManifest and noticed the 
following. You initialize the volatile instance field 'manifest' like 
that:


 609 private volatile Manifest manifest = EMPTY_MANIFEST;


So in following code:

 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 
PrivilegedActionManifest() {

 643 public Manifest run() {
 644 return loadManifest(fileName);
 645 }
 646 });
 647 }
 648 }
 649 }



... loadManifest() will never be executed. getManifest() will always 
return EMPTY_MANIFEST.


You probably wanted line 637 to be written as:

if (manivest != EMPTY_MANIFEST || url == null) { ...


Likewise in loadManifest(), wou write:

 586 private static Manifest loadManifest(String fn) {
 587 try (FileInputStream fis = new FileInputStream(fn);
 588  JarInputStream jis = new JarInputStream(fis, false))
 589 {
 590 return jis.getManifest();
 591 } catch (IOException e) {
 592 return EMPTY_MANIFEST;
 593 }
 594 }

..but you probably wanted the line 592 to return 'null' instead.


Regards, Peter





Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-13 Thread Peter Levart

On 10/13/2014 05:15 PM, Peter Levart wrote:
Yes, I realized I got this messed up and have prepared a new patch 
which passes tests and includes your previous

comments:

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



Hi Claes,

Hm, CachedManifest.getManifest() in 4th webrev is still a little faulty. 
It sometimes returns EMPTY_MANIFEST and sometimes null. I think it 
should always return null in case when no manifest is found (at least 
that was the old code behaviour).


Regards, Peter


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-13 Thread Claes Redestad

On 10/13/2014 05:29 PM, Peter Levart wrote:

On 10/13/2014 05:15 PM, Peter Levart wrote:
Yes, I realized I got this messed up and have prepared a new patch 
which passes tests and includes your previous

comments:

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



Hi Claes,

Hm, CachedManifest.getManifest() in 4th webrev is still a little 
faulty. It sometimes returns EMPTY_MANIFEST and sometimes null. I 
think it should always return null in case when no manifest is found 
(at least that was the old code behaviour).


Hmm, yes, that last little detail of making sure we also set m before 
returning:


-manifest = (m == null ? EMPTY_MANIFEST : m);
+manifest = m = (m == null ? EMPTY_MANIFEST : m);

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

We rely on returning a non-null manifest from 
CachedManifest.getManifest() in the current code, so returning null 
would be a bad idea unless we revert the simplifications to 
defineSystemPackage.


/Claes



Regards, Peter




Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-13 Thread Peter Levart

On 10/13/2014 05:41 PM, Claes Redestad wrote:

On 10/13/2014 05:29 PM, Peter Levart wrote:

On 10/13/2014 05:15 PM, Peter Levart wrote:
Yes, I realized I got this messed up and have prepared a new patch 
which passes tests and includes your previous

comments:

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



Hi Claes,

Hm, CachedManifest.getManifest() in 4th webrev is still a little 
faulty. It sometimes returns EMPTY_MANIFEST and sometimes null. I 
think it should always return null in case when no manifest is found 
(at least that was the old code behaviour).


Hmm, yes, that last little detail of making sure we also set m before 
returning:


-manifest = (m == null ? EMPTY_MANIFEST : m);
+manifest = m = (m == null ? EMPTY_MANIFEST : m);

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

We rely on returning a non-null manifest from 
CachedManifest.getManifest() in the current code, so returning null 
would be a bad idea unless we revert the simplifications to 
defineSystemPackage.


Right, I missed that part.

Peter



/Claes



Regards, Peter






Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-12 Thread Peter Levart


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 
PrivilegedActionManifest() {
 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



Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-12 Thread Peter Levart


On 10/12/2014 12:40 PM, Peter Levart wrote:
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.



..Ah, you can do that, yes, but then you have to use synchronization in 
createCachedManifest in order to avoid redundant concurrent loading of 
Manifest. And that would be a good thing since then you avoid concurrent 
resolving of fileName - URL too in one go.


Peter



Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-12 Thread Peter Levart


On 10/12/2014 12:52 PM, Peter Levart wrote:


On 10/12/2014 12:40 PM, Peter Levart wrote:
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.



..Ah, you can do that, yes, but then you have to use synchronization 
in createCachedManifest in order to avoid redundant concurrent loading 
of Manifest. And that would be a good thing since then you avoid 
concurrent resolving of fileName - URL too in one go.


Peter



Scrap that. I see now what you wanted to achieve. You wanted to avoid 
synchronization on a single monitor when loading manifests while 
avoiding multiple concurrent loading of same manifest. Lazy loading is 
fine than.


Regards, Peter



Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-12 Thread Bernd Eckenfels
Am Fri, 10 Oct 2014 17:31:41 -0700
schrieb Mandy Chung mandy.ch...@oracle.com:
 I agree with David that getting Package objects are not performance
 critical. On the other hand, the code defining/getting Packages is
 old and deserves some cleanup especially the synchronization part.

Hmm.. isnt the package logic part of the ClassLoader (defineClass)
especially around sealing and security manager? So it would be at
least performance critical for startup time?

Bernd


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-12 Thread David Holmes

Hi Claes,

Looking at version three ...

You seemed to have changed the caching strategy for Packages in the 
classloader. Previously a Package defined by a parent or the system 
would be updated in the current loader's Package map; but now you leave 
them separate so future lookups will always have to traverse the 
hierarchy. This doesn't seem like a performance gain.


Looking at definePackage it seems both old and new code have serious 
race conditions due to a lack of atomicity when checking the 
parent/system packages. A package of the same name could be defined in 
the parent/system after definePackage has called getPackage - and we 
then end up with two same named Packages in different loaders.


No comment on the manifest caching aspect - I'm not familiar enough with 
the existing code.


On 12/10/2014 12:09 PM, Claes Redestad wrote:

On 2014-10-11 02:31, Mandy Chung wrote:


On 10/10/2014 8:10 AM, Claes Redestad wrote:

Hi all,

please review this patch which attempts to clean up synchronization
and improve scalability when
defining and getting java.lang.Package objects.


I agree with David that getting Package objects are not performance
critical. On the other hand, the code defining/getting Packages is
old and deserves some cleanup especially the synchronization part.

If you run helloworld program, how does that change the list of loaded
classes besides the new CachedManifest class?



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


ClassLoader.java
line 272: can you change the declared type as Map.


Map misses the atomicity requirement of putIfAbsent, ConcurrentMap is OK
but leaves some
related questions open (why we can't add a null value, specifically).
I'm glad it was brought up
and discussed and will use ConcurrentHashMap for private fields unless
there's a strong
preference otherwise.



definePackage throws IAE if there exists an existing package either
in this class loader or one of its ancestors.
  - this change would not catch if two definePackage calls to define
  a package of the same name but with different spec version, title, etc
  concurrently.

  You may not be able to avoid synchronizing on packages for this case.


Right, I was I think synchronization can still be avoided by throwing
IAE if
putIfAbsent doesn't return null:

 if (packages.putIfAbsent(name, pkg) != null) {
 throw new IllegalArgumentException(name);
 }
 return pkg;



move line 1623 to 1630 so that the declaration of map is closer to
the assignment.


Ok



Package.java

line 557 there is a possibility that new Package[pkgs.size()] is not
big enough and a new array would be created.  As this method is not
popularly used, it's okay if another array is created.


Yes, an unlikely race.



line 563 and 565 can be merged

line 570-575: do you think you can modify the private
  Package(String name, Manifest man, URL url, ClassLoader loader)
constructor
to take null Manifest and null url so that these lines can be folded into

pkg = new Package(name,  cachedManifest.getManifest(),
cachedManifest.getURL(), null);


I think I'll take your suggestion below and ensure cachedManifest and
it's getManifest()
never evaluate to null, which makes for a cleaner patch. There is some
code duplication
here with URLClassLoader#definePackage. Future cleanup?

It would seem the ClassLoader argument in this ctor is always called
with null. Remove?



I think CachedManifest class and the createCachedManifest method need
some work.  Perhaps we can have the CachedManifest constructor to
obtain the URL.

Each invalid fn will have one instance instead of NO_MANIFEST singleton
but that should not happen as fn is the filename where the classes
loaded from the bootclasspath.  CachedManifest.url can then become final.

line 587-601 would not be needed. Can we avoid line 606 and write
the createCachedManifest method this way:
   if (!manifests.containsKey(fn)) {
   manifests.putIfAbsent(fn, new CachedManifest(fn));
   }
   return manifests.get(fn);


Yes. Looked a bit dangerous, but it seems we still maintain the
necessary guarantees.



You may be able to further simplify CachedManifest and remove the
resolved
field by storing an empty Manifest when loadManifest returns null.
That may help the private Package constructor not require any change
to merge line 570-575 as my comment noted above.


Sure! 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/

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 

Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-11 Thread Remi Forax

Hi Mandy,

On 10/11/2014 02:31 AM, Mandy Chung wrote:

[...]





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


ClassLoader.java
line 272: can you change the declared type as Map.


I think it's a bad idea, the class doesn't work if you replace the 
ConcurrentHashMap by any Map

so declaring the field 'packages' as a Map seems wrong to me.
At least, it should be a ConcurrentMap, but even with a ConcurrentMap, I 
think that the guarantee
that in definePackage the call to putIfAbstent is amortized O(1) and not 
something like O(ln n) is important.


Note that using interfaces instead of implementations is important in 
the signature of public or protected method,
for a local variable or a private field, which are hidden, there is no 
real reason to use an interface.
I understand that pedagogically having only one rule is appealing but 
from my own experience, this rule hide
one of the corner stone of the OOP, encapsulation, so IMO the rule 'use 
an interface everywhere you can'
does more harm than good because it offers a discorded version of the OO 
world.


cheers,
Rémi



Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-11 Thread Stanimir Simeonoff
The commented annotation in ClassLoader.java must be removed (line 268)
// @GuardedBy(itself)

Stanimir


On Fri, Oct 10, 2014 at 6:10 PM, Claes Redestad claes.redes...@oracle.com
wrote:

 Hi all,

 please review this patch which attempts to clean up synchronization and
 improve scalability when
 defining and getting java.lang.Package objects.

 webrev: http://cr.openjdk.java.net/~redestad/8060130/webrev.02/
 bug: https://bugs.openjdk.java.net/browse/JDK-8060130

 Testing: jtreg, UTE vm.parallel_class_loading.testlist, various benchmarks

 Torturing the retrieval code with a simple microbenchmark[1] shows that
 the existing code
 could cause bottlenecks, but also that the proposed patch works slightly
 faster even in
 uncontended cases:

 Benchmark   Mode  Samples   Score Score error
  Units
 baseline, 1 thread:
 o.s.SimpleBench.getClassPackagethrpt   10 11.6210.618
 ops/us
 o.s.SimpleBench.getPackage thrpt   10 41.7543.381
 ops/us
 o.s.SimpleBench.getPackagesthrpt   10 0.0090.000
 ops/us

 baseline, 2 threads:
 o.s.SimpleBench.getClassPackagethrpt   10 7.8841.977
 ops/us
 o.s.SimpleBench.getPackage thrpt   10 17.0138.079
 ops/us
 o.s.SimpleBench.getPackagesthrpt   10 0.0040.001
 ops/us

 patch applied, 1 thread:
 o.s.SimpleBench.getClassPackagethrpt   10 13.5190.170
 ops/us
 o.s.SimpleBench.getPackage thrpt   10 59.9990.988
 ops/us
 o.s.SimpleBench.getPackagesthrpt   10 0.0190.001
 ops/us

 patch applied, 2 threads:
 o.s.SimpleBench.getClassPackagethrpt   10 19.1813.688
 ops/us
 o.s.SimpleBench.getPackage thrpt   10 79.708   31.220
 ops/us
 o.s.SimpleBench.getPackagesthrpt   10 0.0250.006
 ops/us

 /Claes

 [1]
 package org.sample;

 import org.openjdk.jmh.annotations.*;

 @State(Scope.Thread)
 public class SimpleBench {

 @Benchmark
 public Package[] getPackages() {
 return Package.getPackages();
 }

 @Benchmark
 public Package getClassPackage() {
 return this.getClass().getPackage();
 }

 @Benchmark
 public Package getPackage() {
 return Package.getPackage(java.util.zip);
 }
 }




Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-11 Thread Mandy Chung


On 10/11/2014 8:17 AM, Remi Forax wrote:

Hi Mandy,

On 10/11/2014 02:31 AM, Mandy Chung wrote:

[...]





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


ClassLoader.java
line 272: can you change the declared type as Map.


I think it's a bad idea, the class doesn't work if you replace the 
ConcurrentHashMap by any Map

so declaring the field 'packages' as a Map seems wrong to me.
At least, it should be a ConcurrentMap, but even with a ConcurrentMap, 
I think that the guarantee
that in definePackage the call to putIfAbstent is amortized O(1) and 
not something like O(ln n) is important.


Note that using interfaces instead of implementations is important in 
the signature of public or protected method, for a local variable or a 
private field, which are hidden, there is no real reason to use an 
interface. I understand that pedagogically having only one rule is 
appealing but from my own experience, this rule hide one of the corner 
stone of the OOP, encapsulation, so IMO the rule 'use an interface 
everywhere you can' does more harm than good because it offers a 
discorded version of the OO world.


Remi - thanks for catching this.  After I sent the comment, I was 
pondering my suggestion (this specific one) was a bad idea. Declaring it 
as Map loses the significance that the implementation depends on the 
packages map being concurrently accessed.   Agree.


Mandy


Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-11 Thread Claes Redestad

On 2014-10-11 02:31, Mandy Chung wrote:


On 10/10/2014 8:10 AM, Claes Redestad wrote:

Hi all,

please review this patch which attempts to clean up synchronization 
and improve scalability when

defining and getting java.lang.Package objects.


I agree with David that getting Package objects are not performance
critical. On the other hand, the code defining/getting Packages is
old and deserves some cleanup especially the synchronization part.

If you run helloworld program, how does that change the list of loaded
classes besides the new CachedManifest class?



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


ClassLoader.java
line 272: can you change the declared type as Map.


Map misses the atomicity requirement of putIfAbsent, ConcurrentMap is OK 
but leaves some
related questions open (why we can't add a null value, specifically). 
I'm glad it was brought up
and discussed and will use ConcurrentHashMap for private fields unless 
there's a strong

preference otherwise.



definePackage throws IAE if there exists an existing package either
in this class loader or one of its ancestors.
  - this change would not catch if two definePackage calls to define
  a package of the same name but with different spec version, title, etc
  concurrently.

  You may not be able to avoid synchronizing on packages for this case.


Right, I was I think synchronization can still be avoided by throwing IAE if
putIfAbsent doesn't return null:

if (packages.putIfAbsent(name, pkg) != null) {
throw new IllegalArgumentException(name);
}
return pkg;



move line 1623 to 1630 so that the declaration of map is closer to
the assignment.


Ok



Package.java

line 557 there is a possibility that new Package[pkgs.size()] is not
big enough and a new array would be created.  As this method is not
popularly used, it's okay if another array is created.


Yes, an unlikely race.



line 563 and 565 can be merged

line 570-575: do you think you can modify the private
  Package(String name, Manifest man, URL url, ClassLoader loader) 
constructor

to take null Manifest and null url so that these lines can be folded into

pkg = new Package(name,  cachedManifest.getManifest(), 
cachedManifest.getURL(), null);


I think I'll take your suggestion below and ensure cachedManifest and 
it's getManifest()
never evaluate to null, which makes for a cleaner patch. There is some 
code duplication

here with URLClassLoader#definePackage. Future cleanup?

It would seem the ClassLoader argument in this ctor is always called 
with null. Remove?




I think CachedManifest class and the createCachedManifest method need
some work.  Perhaps we can have the CachedManifest constructor to
obtain the URL.

Each invalid fn will have one instance instead of NO_MANIFEST singleton
but that should not happen as fn is the filename where the classes
loaded from the bootclasspath.  CachedManifest.url can then become final.

line 587-601 would not be needed. Can we avoid line 606 and write
the createCachedManifest method this way:
   if (!manifests.containsKey(fn)) {
   manifests.putIfAbsent(fn, new CachedManifest(fn));
   }
   return manifests.get(fn);


Yes. Looked a bit dangerous, but it seems we still maintain the 
necessary guarantees.




You may be able to further simplify CachedManifest and remove the 
resolved

field by storing an empty Manifest when loadManifest returns null.
That may help the private Package constructor not require any change
to merge line 570-575 as my comment noted above.


Sure! 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/

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?



You will need to check there is any test to verify Package created with
and without manifest.  Do you mind making this change and tests (I 
realize

it might be out of scope of this performance improvement you initially
anticipated)?


I'll take a look at the current test coverage and give it some thought.

Thanks!

/Claes



Mandy





Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-10 Thread David Holmes

Hi Claes,

On 11/10/2014 1:10 AM, Claes Redestad wrote:

Hi all,

please review this patch which attempts to clean up synchronization and
improve scalability when defining and getting java.lang.Package objects.


Is this a real problem or a theoretical one? I've not previously heard 
of getting Package objects as being critical. ConcurrentHashMap improves 
the contended case but if we aren't normally contended then it will 
degrade performance. How does this perform on real code?


I'm also wondering how this impacts the initialization order of the VM 
as we need a lot more classes to be loaded and initialized when the 
first Package is created.


Thanks,
David


webrev: http://cr.openjdk.java.net/~redestad/8060130/webrev.02/
bug: https://bugs.openjdk.java.net/browse/JDK-8060130

Testing: jtreg, UTE vm.parallel_class_loading.testlist, various benchmarks

Torturing the retrieval code with a simple microbenchmark[1] shows that
the existing code
could cause bottlenecks, but also that the proposed patch works slightly
faster even in
uncontended cases:

Benchmark   Mode  Samples   Score Score error Units
baseline, 1 thread:
o.s.SimpleBench.getClassPackagethrpt   10 11.6210.618
ops/us
o.s.SimpleBench.getPackage thrpt   10 41.7543.381
ops/us
o.s.SimpleBench.getPackagesthrpt   10 0.0090.000
ops/us

baseline, 2 threads:
o.s.SimpleBench.getClassPackagethrpt   10 7.8841.977
ops/us
o.s.SimpleBench.getPackage thrpt   10 17.0138.079
ops/us
o.s.SimpleBench.getPackagesthrpt   10 0.0040.001
ops/us

patch applied, 1 thread:
o.s.SimpleBench.getClassPackagethrpt   10 13.5190.170
ops/us
o.s.SimpleBench.getPackage thrpt   10 59.9990.988
ops/us
o.s.SimpleBench.getPackagesthrpt   10 0.0190.001
ops/us

patch applied, 2 threads:
o.s.SimpleBench.getClassPackagethrpt   10 19.1813.688
ops/us
o.s.SimpleBench.getPackage thrpt   10 79.708   31.220
ops/us
o.s.SimpleBench.getPackagesthrpt   10 0.0250.006
ops/us

/Claes

[1]
package org.sample;

import org.openjdk.jmh.annotations.*;

@State(Scope.Thread)
public class SimpleBench {

 @Benchmark
 public Package[] getPackages() {
 return Package.getPackages();
 }

 @Benchmark
 public Package getClassPackage() {
 return this.getClass().getPackage();
 }

 @Benchmark
 public Package getPackage() {
 return Package.getPackage(java.util.zip);
 }
}



Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-10 Thread Claes Redestad

Hi David!

On 10/10/2014 05:22 PM, David Holmes wrote:

Hi Claes,

On 11/10/2014 1:10 AM, Claes Redestad wrote:

Hi all,

please review this patch which attempts to clean up synchronization and
improve scalability when defining and getting java.lang.Package objects.


Is this a real problem or a theoretical one?
Deadlocks in getPackage() have historically caused issues 
(https://bugs.openjdk.java.net/browse/JDK-7001933), so contention can 
happen. Still somewhat theoretical, though.
I've not previously heard of getting Package objects as being 
critical. ConcurrentHashMap improves the contended case but if we 
aren't normally contended then it will degrade performance. How does 
this perform on real code?
Experiments (like the trivial microbenchmark below) indicate this 
improves performance even in uncontended cases, which can probably be 
explained by the removal of explicit synchronization in favor of 
volatile reads inside CHM. I've run a number of larger benchmarks mostly 
to ensure there are no unexpected regressions, but not found a case 
where this patch has a significant impact. There's a small footprint win 
in effect by merging two maps in java.lang.Package and not saving 
ancestral entries in the ClassLoader packages map which shows up on some 
footprint measures and might have more impact when scaling up to larger 
apps.


I'm also wondering how this impacts the initialization order of the VM 
as we need a lot more classes to be loaded and initialized when the 
first Package is created.
Since this is a concern, I've ran a number of internal startup 
benchmarks but not found the changes to have any statistical significant 
startup impact in either direction. Since ConcurrentHashMap is already 
in use by any parallel capable java.lang.ClassLoader, java.lang.Thread 
etc, it would seem it'll already be loaded and initialized early.


/Claes



Thanks,
David


webrev: http://cr.openjdk.java.net/~redestad/8060130/webrev.02/
bug: https://bugs.openjdk.java.net/browse/JDK-8060130

Testing: jtreg, UTE vm.parallel_class_loading.testlist, various 
benchmarks


Torturing the retrieval code with a simple microbenchmark[1] shows that
the existing code
could cause bottlenecks, but also that the proposed patch works slightly
faster even in
uncontended cases:

Benchmark   Mode  Samples   Score Score error 
Units

baseline, 1 thread:
o.s.SimpleBench.getClassPackagethrpt   10 11.621 0.618
ops/us
o.s.SimpleBench.getPackage thrpt   10 41.754 3.381
ops/us
o.s.SimpleBench.getPackagesthrpt   10 0.009 0.000
ops/us

baseline, 2 threads:
o.s.SimpleBench.getClassPackagethrpt   10 7.884 1.977
ops/us
o.s.SimpleBench.getPackage thrpt   10 17.013 8.079
ops/us
o.s.SimpleBench.getPackagesthrpt   10 0.004 0.001
ops/us

patch applied, 1 thread:
o.s.SimpleBench.getClassPackagethrpt   10 13.519 0.170
ops/us
o.s.SimpleBench.getPackage thrpt   10 59.999 0.988
ops/us
o.s.SimpleBench.getPackagesthrpt   10 0.019 0.001
ops/us

patch applied, 2 threads:
o.s.SimpleBench.getClassPackagethrpt   10 19.181 3.688
ops/us
o.s.SimpleBench.getPackage thrpt   10 79.708 31.220
ops/us
o.s.SimpleBench.getPackagesthrpt   10 0.025 0.006
ops/us

/Claes

[1]
package org.sample;

import org.openjdk.jmh.annotations.*;

@State(Scope.Thread)
public class SimpleBench {

 @Benchmark
 public Package[] getPackages() {
 return Package.getPackages();
 }

 @Benchmark
 public Package getClassPackage() {
 return this.getClass().getPackage();
 }

 @Benchmark
 public Package getPackage() {
 return Package.getPackage(java.util.zip);
 }
}





Re: RFR: 8060130: Simplify the synchronization of defining and getting java.lang.Package

2014-10-10 Thread Mandy Chung


On 10/10/2014 8:10 AM, Claes Redestad wrote:

Hi all,

please review this patch which attempts to clean up synchronization 
and improve scalability when

defining and getting java.lang.Package objects.


I agree with David that getting Package objects are not performance
critical. On the other hand, the code defining/getting Packages is
old and deserves some cleanup especially the synchronization part.

If you run helloworld program, how does that change the list of loaded
classes besides the new CachedManifest class?



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


ClassLoader.java
line 272: can you change the declared type as Map.

definePackage throws IAE if there exists an existing package either
in this class loader or one of its ancestors.
  - this change would not catch if two definePackage calls to define
  a package of the same name but with different spec version, title, etc
  concurrently.

  You may not be able to avoid synchronizing on packages for this case.

move line 1623 to 1630 so that the declaration of map is closer to
the assignment.

Package.java

line 557 there is a possibility that new Package[pkgs.size()] is not
big enough and a new array would be created.  As this method is not
popularly used, it's okay if another array is created.

line 563 and 565 can be merged

line 570-575: do you think you can modify the private
  Package(String name, Manifest man, URL url, ClassLoader loader) constructor
to take null Manifest and null url so that these lines can be folded into
 
pkg = new Package(name,  cachedManifest.getManifest(),  cachedManifest.getURL(), null);


I think CachedManifest class and the createCachedManifest method need
some work.  Perhaps we can have the CachedManifest constructor to
obtain the URL.

Each invalid fn will have one instance instead of NO_MANIFEST singleton
but that should not happen as fn is the filename where the classes
loaded from the bootclasspath.  CachedManifest.url can then become final.

line 587-601 would not be needed. Can we avoid line 606 and write
the createCachedManifest method this way:
   if (!manifests.containsKey(fn)) {
   manifests.putIfAbsent(fn, new CachedManifest(fn));
   }
   return manifests.get(fn);

You may be able to further simplify CachedManifest and remove the resolved
field by storing an empty Manifest when loadManifest returns null.
That may help the private Package constructor not require any change
to merge line 570-575 as my comment noted above.

You will need to check there is any test to verify Package created with
and without manifest.  Do you mind making this change and tests (I realize
it might be out of scope of this performance improvement you initially
anticipated)?

Mandy