RFE: Refactor java.util.Optional and add NonNull checks
Oleksii Kucheruk
iselo+openjdk at raccoons.co
Mon Aug 28 12:17:23 UTC 2023
Now it is clear. Sorry for the inconvenience. Thank you for your time. I
appreciate.
On Mon, 28 Aug 2023 at 2:03 PM Quân Anh Mai <anhmdq at gmail.com> wrote:
> Tbh I have a hard time understand what you are trying to convey. Please
> write grammatically correct sentences with clear structure.
>
> I notice you attach benchmark results but I don't see what was benchmarked
> to produce those results.
>
> Another point is that Value classes has not been delivered yet, so there
> are potential performance uplifts of Optional in the future. This may not
> be possible if Optional is polymorphic.
>
> Thanks
>
> On Mon, 28 Aug 2023 at 18:27, Oleksii Kucheruk <iselo+openjdk at raccoons.co>
> wrote:
>
>> Thank you Quân.
>>
>> All you saying guys make sense.
>> Yes there is a difference calling methods by pointer and involving
>> vtable. But one thing didn't came out of my head:
>> If virtual dispatch dispatch is 10-time more expensive and polymorphism
>> is a performance killer so how combinations of "return optional -
>> isPresent- get" or "return empty - isEmpty" with virtual dispatch and
>> memory allocation for every empty or sole but polymorph empty could perform
>> equally or even beat the near zero-cost abstraction of Value classes
>> according to JMH?
>>
>> Maybe private final static nested EmptyOptional invokevirtual bytecode refers
>> a final methods and it need not have a vtable slot allocated. This means
>> that, after linking, an invokevirtual bytecode might in fact collapse into
>> the equivalent of an invokestatic bytecode.
>> The question of full dynamic with anonymous overloading is still unclear
>> to me.
>>
>> Benchmark Mode Cnt
>> Score Error Units
>>
>> *OptionalComboIsPresentGet.opDynamicAnonymous thrpt 30
>> 1059868995.937 ± 51273067.116 ops/s*
>>
>> OptionalComboIsPresentGet.opJdk thrpt 30 1017505800.567
>> ± 16007847.872 ops/s
>>
>> OptionalComboIsPresentGet.opNestedStatic thrpt 30 951493332.957
>> ± 12167812.398 ops/s
>>
>>
>> OptionalComboOfIsPresentGetTest.opDynamicAnonymous thrpt 30 1426348334.485
>> ± 20889455.433 ops/s
>>
>> *OptionalComboOfIsPresentGetTest.opJdk thrpt 30
>> 1435570789.822 ± 16587538.659 ops/s*
>>
>> OptionalComboOfIsPresentGetTest.opNestedStatic thrpt 30 1418853644.215
>> ± 27755398.645 ops/s
>>
>>
>> *OptionalComboOfNullableIsEmptyTest.opDynamicAnonymous thrpt 30
>> 1434399595.592 ± 14749443.903 ops/s*
>>
>> OptionalComboOfNullableIsEmptyTest.opJdk thrpt 30 1255375023.531
>> ± 107403119.573 ops/s
>>
>> OptionalComboOfNullableIsEmptyTest.opNestedStatic thrpt 30 1415705702.964
>> ± 26328318.672 ops/s
>>
>>
>> OptionalEmptyTest.opDynamicAnonymous thrpt 30 1417895521.763
>> ± 26311640.557 ops/s
>>
>> *OptionalEmptyTest.opJdk thrpt 30
>> 1423940087.962 ± 18515297.860 ops/s*
>>
>> OptionalEmptyTest.opNestedStatic thrpt 30 1424779162.084
>> ± 20288793.337 ops/s
>>
>>
>> OptionalGetTest.emDynamicAnonymous thrpt 30 569132.235
>> ± 11089.903 ops/s
>>
>> *OptionalGetTest.emJdk thrpt 30
>> 549764.038 ± 14768.566 ops/s*
>>
>> OptionalGetTest.emNestedStatic thrpt 30 568308.722
>> ± 6075.671 ops/s
>>
>>
>> OptionalGetTest.opDynamicAnonymous thrpt 30 953788065.414
>> ± 7043419.784 ops/s
>>
>> *OptionalGetTest.opJdk thrpt 30
>> 1015679232.049 ± 11726562.032 ops/s*
>>
>> OptionalGetTest.opNestedStatic thrpt 30 944209513.151
>> ± 17718342.519 ops/s
>>
>>
>> OptionalIsPresentTest.emDynamicAnonymous thrpt 30 869086292.481
>> ± 11668636.886 ops/s
>>
>> *OptionalIsPresentTest.emJdk thrpt 30
>> 977042244.447 ± 44558020.220 ops/s*
>>
>> OptionalIsPresentTest.emNestedStatic thrpt 30 953424664.631
>> ± 8448564.963 ops/s
>>
>>
>> OptionalIsPresentTest.opDynamicAnonymous thrpt 30 953285872.799
>> ± 6562894.941 ops/s
>>
>> *OptionalIsPresentTest.opJdk thrpt 30
>> 1006926903.885 ± 18055487.689 ops/s*
>>
>> OptionalIsPresentTest.opNestedStatic thrpt 30 954121471.431
>> ± 6829528.708 ops/s
>>
>>
>> OptionalOfNullableTest.emDynamicAnonymous thrpt 30 1422939780.266
>> ± 21693247.354 ops/s
>>
>> *OptionalOfNullableTest.emJdk thrpt 30
>> 1423340184.237 ± 21296444.017 ops/s*
>>
>> OptionalOfNullableTest.emNestedStatic thrpt 30 1414965236.385
>> ± 26021734.344 ops/s
>>
>>
>> OptionalOfNullableTest.opDynamicAnonymous thrpt 30 1412594454.538
>> ± 28123612.298 ops/s
>>
>> *OptionalOfNullableTest.opJdk thrpt 30
>> 1427924599.589 ± 23469517.835 ops/s*
>>
>> OptionalOfNullableTest.opNestedStatic thrpt 30 1420053175.637
>> ± 21170929.571 ops/s
>>
>>
>> OptionalOfTest.emDynamicAnonymous thrpt 30 549907.559
>> ± 14560.954 ops/s
>>
>> OptionalOfTest.emJdk thrpt 30 557858.903
>> ± 2851.076 ops/s
>>
>> *OptionalOfTest.emNestedStatic thrpt 30
>> 548655.854 ± 10875.674 ops/s*
>>
>>
>> OptionalOfTest.opDynamicAnonymous thrpt 30 1411307270.435
>> ± 19832207.408 ops/s
>>
>> OptionalOfTest.opJdk thrpt 30 1400651442.726
>> ± 23641065.234 ops/s
>>
>> *OptionalOfTest.opNestedStatic thrpt 30
>> 1433953744.298 ± 21414147.936 ops/s*
>>
>>
>> On Mon, Aug 28, 2023 at 11:13 AM Quân Anh Mai <anhmdq at gmail.com> wrote:
>>
>>> Hi,
>>>
>>> Polymorphism is a performance killer. Normally this does not matter
>>> much, but for thin wrappers such as Optional, this is one of the most
>>> important factor.
>>>
>>> Behaviour polymorphism requires virtual dispatch and prevents inlining.
>>> This is really detrimental, as simple operations such as a getter which is
>>> previously only consisted of a memory load, in the presence of polymorphism
>>> would have to go through a 10-time more expensive virtual dispatch.
>>> Function calls, especially virtual ones, are also opaque and prohibit
>>> compiler optimisations.
>>>
>>> Layout polymorphism prevents direct accesses and requires indirection.
>>> This means that for every instance of Optional created a memory allocation
>>> is required. Optional is expected to be a near zero-cost abstraction in the
>>> presence of Value classes, so making it polymorphic is unacceptable.
>>>
>>> Thanks.
>>>
>>> On Wed, 23 Aug 2023 at 22:43, Oleksii Kucheruk <
>>> iselo+openjdk at raccoons.co> wrote:
>>>
>>>> Hi there.
>>>> I have found that `java.util.Optional` is written procedural style and
>>>> has `ifnonnull` checks in each method. I propose to refactor `Optional` in
>>>> accordance to OOP-style. This will eliminates all unnecessary
>>>> `if`-statements, removes duplications and reduces bytecode size more then
>>>> twice.
>>>>
>>>> I have two solutions:
>>>> 1. Completely dynamic that avoids single static `EMPTY` instance and
>>>> unchecked casting of each `Optional.empty()`
>>>> 2. Preserving original single static `EMPTY` per VM.
>>>>
>>>> Also there are couple methods that throws NPE due to calling methods on
>>>> null-objects and requires to add `Objects.requireNonNull(...)`.
>>>>
>>>> OptionalInt, OptionalDouble, OptionalLong could be refactored same way
>>>> even with remove of additional boolean variable `isPresent`.
>>>>
>>>> Since I'm new here any guidance will be helpful.
>>>> Thank you in advance.
>>>>
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20230828/832e3d98/attachment-0001.htm>
More information about the core-libs-dev
mailing list