I received the following reply, which is worth reading into the record:
Brian,
Let me add my 5 cents here. My fear is that actually removing (making
private) constructors of primitive wrappers will break a lot of code
legacy code out there. In fact, even today we use those constructors
to work around limitations in HotSpot's escape analysis and allocation
elimination. E.g. if you conditionally return the result of
`Integer.valueOf(x)` from a method, then the allocation inside of the
valueOf cannot be eliminated by HotSpot (that allocation is
conditional itself and that is too much for HotSpot to see through),
but if, on the other hand, you conditionally return the result of `new
Integer(x)`, then HotSpot consistently eliminates this allocation.
Sincerely,
Roman Elizarov
It is notable that you bring up escape analysis here. The hiding of the
concrete constructors is something we are undertaking _precisely so we
can migrate these wrappers to inline classes_; making them inline
classes greatly improves the compiler's ability to eliminate
allocations. So I think this concern becomes "your grand plan, which
has as a benefit greatly improved escape analysis, will interfere with
my workarounds to get better escape analysis."
That said, it will take some time for existing uses to migrate away from
these constructors -- all the more reason to deprecate them for removal
earlier.
On 2/19/2020 11:45 AM, Brian Goetz wrote:
One of the main impediments to migrating the primitive wrappers to be
the reference projection of an inline class is locking -- there may be
code out there that locks on instances of primitive wrappers. Let's
look at how we might wean users off, and what the compatibility
constraints really are.
First, note that all the wrappers have had static `valueOf()`
factories, and the corresponding constructors have been deprecated
since Java 9. It would be reasonable to deprecate these for removal
at any time. (These would not actually be removed, but instead made
private.)
Having removed the public constructors, now the only way to get your
hands on an Integer is through some mechanism like `valueOf()`. I
claim now that:
Under such a scheme, any code outside of java.lang that
synchronizes on a wrapper is
inherently broken
That is, it is synchronizing on an object whose locking protocol you
are not party to, which is not guaranteed non-aliased, and which may
in fact be permanently locked by some other thread. Therefore, it is
a forseeable outcome for such a sync attempt to block forever.
This was the intent behind https://openjdk.java.net/jeps/169, though
it wasn't obvious from the title -- the ability to mark certain
objects as permanently locked.
So, concrete proposal:
- Move forward with the deprecation-for-removal of the constructors;
- Add hortatory notes in the spec for `valueOf()` that locking on
objects whose provenance you do not control is a risky business, and
may well never complete;
- Poison instances of primitive wrappers by marking their headers at
creation with a bit pattern that will send locking through the slow
path, where it can see that these are poisoned objects and cause lock
attempts to never complete (or throw)
- Provide a JDK-scoped option to turn off the above behavior
(-Xx:AllowStupidBrokenLockingOnPrimitiveWrappers)
I don't see anything stopping us from doing any of these immediately.