The current support of inline types in C1 is currently very basic and lacks some optimizations that sometimes makes it as inefficient as the interpreter. One example is the implementation of the withfield: each time a withfield bytecode is executed, a new instance is allocated in the Java heap, even when such allocation could be avoided.
Proposed optimization
The withfield bytecode "consumes" an inline type value and a field value and returns a new inline type value with one field updated with the field value. If the inline type value passed to the bytecode is the only reference to this value, it is safe to update it in place instead of creating a new copy before updating the field. Inline type values satisfying the conditions for this optimization are said to be in the "larval" state.
Implementation of the larval state:
In C1 HIR, the creation of a new inline type instance is marked by the insertion of a NewInlineTypeInstance node in the CFG. A new field has been added to the NewInlineTypeInstance node to keep track of values' larval state. When a NewInlineTypeInstance node is created, it is automatically in the larval state, but if any point in time it loses this state, this state is lost for ever.
Usage of the larval state:
When a withfield is applied to a NewInlineTypeInstance in the larval state, the code generated by C1 will perform a field update on the current value instead of generating a copy and updating it. If a withfield is applied to a NewInlineTypeInstance that is not in the larval state, a copy + update code is generated.
Management of the larval state:
There are 3 conditions that could cause a NewInlineTypeInstance node to loose its larval state.
1 - When the value "escapes" by being written to a field, written to an array, being passed as the argument of a method, or being used as the receiver of method being invoked.
2 - When more than one reference to this value are being pushed on the stack, as the result of a dup* operation or by reading it from a local variable slot when there's already a reference on the stack
3 - When the value is stored in more than one local variable slot
When ever one of these conditions is met, the NewInlineTypeInstance node looses its larval state.
The special case of dup_x2/pop
Unfortunately, the code generated by javac to update a long or a double field of an inline type value contains the bytecode sequence "dup_x2/pop" which temporary duplicates the reference to the inline type value. But this particular sequence can easily be identified and handle specially to prevent the NewInlineTypeInstance node to loose its larval state in this case.
Handling in the phi function
The current implementation has a very conservative approach and whenever a NewInlineTypeInstance appears as an argument of a phi function, it loses its larval state. It might be possible to relax this rule in the future, and keep the larval state if all NewInlineTypeInstance arguments of the phi function are in a larval state.
Proposed optimization
The withfield bytecode "consumes" an inline type value and a field value and returns a new inline type value with one field updated with the field value. If the inline type value passed to the bytecode is the only reference to this value, it is safe to update it in place instead of creating a new copy before updating the field. Inline type values satisfying the conditions for this optimization are said to be in the "larval" state.
Implementation of the larval state:
In C1 HIR, the creation of a new inline type instance is marked by the insertion of a NewInlineTypeInstance node in the CFG. A new field has been added to the NewInlineTypeInstance node to keep track of values' larval state. When a NewInlineTypeInstance node is created, it is automatically in the larval state, but if any point in time it loses this state, this state is lost for ever.
Usage of the larval state:
When a withfield is applied to a NewInlineTypeInstance in the larval state, the code generated by C1 will perform a field update on the current value instead of generating a copy and updating it. If a withfield is applied to a NewInlineTypeInstance that is not in the larval state, a copy + update code is generated.
Management of the larval state:
There are 3 conditions that could cause a NewInlineTypeInstance node to loose its larval state.
1 - When the value "escapes" by being written to a field, written to an array, being passed as the argument of a method, or being used as the receiver of method being invoked.
2 - When more than one reference to this value are being pushed on the stack, as the result of a dup* operation or by reading it from a local variable slot when there's already a reference on the stack
3 - When the value is stored in more than one local variable slot
When ever one of these conditions is met, the NewInlineTypeInstance node looses its larval state.
The special case of dup_x2/pop
Unfortunately, the code generated by javac to update a long or a double field of an inline type value contains the bytecode sequence "dup_x2/pop" which temporary duplicates the reference to the inline type value. But this particular sequence can easily be identified and handle specially to prevent the NewInlineTypeInstance node to loose its larval state in this case.
Handling in the phi function
The current implementation has a very conservative approach and whenever a NewInlineTypeInstance appears as an argument of a phi function, it loses its larval state. It might be possible to relax this rule in the future, and keep the larval state if all NewInlineTypeInstance arguments of the phi function are in a larval state.