Re: Value types - compatibility with existing “value objects”

Vitaly Davidovich vitalyd at gmail.com
Thu Jan 8 18:49:02 UTC 2015


Let me preface that for your simple example, I'd hope the JVM can optimize
this where it boils down to simply reading biggie.a33 without any copying
and method calls.  However, I take the point where this may not be the case.

How would the box be created in this case? Would it be a "view" over the
memory range covered by biggie inside the Foo instance? I'm guessing this
box is not an actual heap allocated box with the data copied into it,
because now you're back to copying.  So, is the idea that the VM can "box"
in different ways, sometimes making a full heap copy (because perhaps
someone then uses the box as an object, e.g. synchronizing on it) and at
other times creating a slice/view over some bit of memory?

I guess my point is that if I authored a value type with 1000/"very large #
of" fields, then I'm clearly saying I'm ok with having this passed around
and copied.  The problem with boxing operations that are invisible and also
auto-tuned by the JVM is that it may not always make the most optimal
choice (e.g. older JVM running on newer hardware where the # of registers,
cache line size, and/or any other parameter have changed).  Are you then
going to expose more JVM tunables/flags to allow users to control this?
Seems like a lot of complexity to handle an edge case (i.e. I don't expect
developers to create ridiculously large value types; that certainly hasn't
been my experience on the .NET side of things).  Also, perhaps I don't care
about wasting stack space and incurring the copy cost, but want to avoid
heap allocations at all cost.

Another consideration is atomicity, for values that need to be guaranteed
> tear-free.  If they fit into a cache line, there's probably already a free
> atomic update mechanism available to the VM; if the value is big, the VM
> might prefer to box the value and CAS on the reference. (Or maybe there's
> hardware TM available.)  We let the VM make these choices.


Not sure how boxing the value and CAS'ing on the reference would work --
how would the new object be copied back into the "inlined" value storage of
the owning object? Using the Foo + VVV example above, how would that work
exactly?

I'm not even sure it's a good idea (at least for v1) to make any promises
around tearing/atomicity of value types.  Outside of HTM, modern hardware
does not support arbitrary width atomic operations.  I would make the user
use locks/synchronization to update the value types.  For cases where you
have a small struct (e.g. wraps an int32) and want to treat like
AtomicInteger/etc, then they could always store the value internally as an
int, but work with it using the value type.

On Thu, Jan 8, 2015 at 1:27 PM, Brian Goetz <brian.goetz at oracle.com> wrote:

> Why is # of registers a factor here? I'd expect some # of registers to
>> be used for passing some of the values (depending on calling
>> convention), and the rest passed on the stack.
>>
>> This is also the first I hear of VM reserving the right to transparently
>> box depending on some size threshold.  My preference would be to simply
>> use the stack, and if you run out of stack, handle that the same way as
>> today.  Clearly someone passing a giant value type around is not doing
>> themselves any good, but the automagic boxing behind the scenes doesn't
>> sit well.  What if boxing that giant value type causes an OOM? I don't
>> think that would be expected.
>>
>
> That would be taking away a valuable degree of freedom for the VM to
> optimize.
>
> Suppose you have a big value type VVV with 1000 fields, a1 .. a1000. Now
> you have:
>
> class Foo {
>    VVV biggie;
> }
>
> and a method:
>
> void getA33(VVV biggie) { return biggie.a33; }
>
> and a call
>
> getA33(foo.biggie);
>
> Do you want to push 1000 elements on the stack just to pick #33?  The
> "value" is already on the heap, in the "biggie" field of Foo.  Why not let
> the VM pass it by reference, saying "that's the big value you want, over
> there", and let the VM make the tradeoff based on the relative cost of
> copying N elements to the stack vs the indirection to the heap?
>
> The bytecodes define the semantics; the VM should be free to pass via
> registers or stack or heap or smoke signals based on what it decides is the
> best.
>
> The size of register files and stack segments will likely be one input
> into these calculations.
>
>
>
> Another consideration is atomicity, for values that need to be guaranteed
> tear-free.  If they fit into a cache line, there's probably already a free
> atomic update mechanism available to the VM; if the value is big, the VM
> might prefer to box the value and CAS on the reference. (Or maybe there's
> hardware TM available.)  We let the VM make these choices.
>
>


More information about the valhalla-dev mailing list