To me, getting fancy here sounds like borrowing trouble; it seems much simpler -- and perfectly reasonable -- to reject cycles at both compile and runtime, and let users use `V?` in the place they want to break their cycles.  (Assuming we're comfortable with `V?` means not flattened, which is the choice we're also making for specialization.)

On 4/11/2019 4:22 PM, Frederic Parain wrote:
On Apr 11, 2019, at 15:20, Karen Kinnear <[email protected]> wrote:

2. circularity handling for value type fields - proposed experiment with vm 
detection
Remi: if VM determines where to “stop” flattening the results will be random 
locations - which will change performance
Karen: Frederic prototyping in progress -
     - choice of field to flatten is random: based on dynamic loading order
John: give tools responsibility, so vm doesn’t make the decision, potential 
user model issue
(ed. note: more discussion to come - including options such as not flattening 
any field involved in circularity/performance cost, tool choice, user model 
choice)
Here’s the results of the exploration:
   1 - The JVM could be able to deal with cycles by stopping field flattening.
        The class loading and field layout computation have been updated to
        support cycles without major issues. CI was not fixed, it currently 
enters
        an infinite recursive loop, but after a discussion with Tobias, it 
seems that
        we should be able to handle that properly.

   2 - The next question is what to do when a cycle is detected. The solution
        implemented in the prototype was to try to flattened as much as 
possible,
        and to refuse to flatten the last field closing the cycle. The problem 
with this
        strategy is that the layout of data structures depends on the first 
class of the cycle
        that is loaded. For the end user, this means that performance will 
depends
        on class loading order, something that the user doesn’t necessarily 
controls.

        Example with the test program attached to this mail. The argument 
controls
        execution of different branches which trigger class loading in 
different order.
        Then, whatever argument has been passed, the same loop is executed
        (runs are using the interpreter because of the CI issue, with a JIT, the
         differences should be less significant) :

fparain-mac:valhalla fparain$ ./build/macosx-x64-debug/jdk/bin/java 
-XX:+EnableValhalla -Xint CycleTest A
Average: 647.0 ops/ms
fparain-mac:valhalla fparain$ ./build/macosx-x64-debug/jdk/bin/java 
-XX:+EnableValhalla -Xint CycleTest B
Average: 890.0 ops/ms
fparain-mac:valhalla fparain$ ./build/macosx-x64-debug/jdk/bin/java 
-XX:+EnableValhalla -Xint CycleTest C
Average: 642.0 ops/ms

        And the explanation of the difference of throughput comes directly from
        the difference of layouts:

        With argument A:

Class CycleTest$A [@app]:
   @ 16  "i" I
   @ 24  "b" QCycleTest$B;  // flattenable and flattened
   @ 24     "j" I
   @ 32     "c" QCycleTest$C;  // flattenable and flattened
   @ 32        "k" I
   @ 36        "a" QCycleTest$A;  // flattenable not flattened

       With argument B:

Class CycleTest$A [@app]:
   @ 16  "i" I
   @ 20  "b" QCycleTest$B;  // flattenable not flattened

    With argument C:

Class CycleTest$A [@app]:
   @ 16  "i" I
   @ 24  "b" QCycleTest$B;  // flattenable and flattened
   @ 24     "j" I
   @ 28     "c" QCycleTest$C;  // flattenable not flattened

    Dan suggested another strategy to ensure consistent layouts and 
performances: whenever a cycle
    is detected, non of the field involved in this cycle is flattened. We can 
implement this solution too.

    The other solutions that have been proposed rely on the user or javac to 
prevent the creation of
    cycles. These solutions don’t require modification of the JVM, it would 
keep its current behavior
    which is to throw a ClassCircularityError when it detects a cycle.

Fred






Reply via email to