Re: RFR: 8322292: Rearrange comparison of fields in Record.equals() [v6]

2024-01-20 Thread Sergey Tsypanov
On Fri, 22 Dec 2023 13:00:11 GMT, Sergey Tsypanov  wrote:

>> Currently if we create a record it's fields are compared in their 
>> declaration order. This might be ineffective in cases when two objects have 
>> "heavy" fields equals to each other, but different "lightweight" fields 
>> (heavy and lightweight in terms of comparison) e.g. primitives, enums, 
>> nullable/non-nulls etc.
>> 
>> If we have declared a record like
>> 
>> public record MyRecord(String field1, int field2) {}
>> 
>> It's equals() looks like:
>> 
>>   public final equals(Ljava/lang/Object;)Z
>>L0
>> LINENUMBER 3 L0
>> ALOAD 0
>> ALOAD 1
>> INVOKEDYNAMIC 
>> equals(Lcom/caspianone/openbanking/productservice/controller/MyRecord;Ljava/lang/Object;)Z
>>  [
>>   // handle kind 0x6 : INVOKESTATIC
>>   
>> java/lang/runtime/ObjectMethods.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
>>   // arguments:
>>   com.caspianone.openbanking.productservice.controller.MyRecord.class,
>>   "field1;field2",
>>   // handle kind 0x1 : GETFIELD
>>   
>> com/caspianone/openbanking/productservice/controller/MyRecord.field1(Ljava/lang/String;),
>>   // handle kind 0x1 : GETFIELD
>>   com/caspianone/openbanking/productservice/controller/MyRecord.field2(I)
>> ]
>> IRETURN
>>L1
>> LOCALVARIABLE this 
>> Lcom/caspianone/openbanking/productservice/controller/MyRecord; L0 L1 0
>> LOCALVARIABLE o Ljava/lang/Object; L0 L1 1
>> MAXSTACK = 2
>> MAXLOCALS = 2
>> 
>> This can be improved by rearranging the comparison order of the fields 
>> moving enums and primitives upper, and collections/arrays lower.
>
> Sergey Tsypanov has updated the pull request incrementally with two 
> additional commits since the last revision:
> 
>  - Merge remote-tracking branch 'origin/record-equals' into record-equals
>  - 8322292: Add test case

Anything else I can do about it?

-

PR Comment: https://git.openjdk.org/jdk/pull/17143#issuecomment-1902184686


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals() [v5]

2023-12-22 Thread Sergey Tsypanov
On Thu, 21 Dec 2023 19:43:50 GMT, ExE Boss  wrote:

>> src/java.base/share/classes/java/lang/runtime/ObjectMethods.java line 224:
>> 
>>> 222: var rt2 = mh2.type().returnType();
>>> 223: return Integer.compare(
>>> 224: rt1.isPrimitive() || rt1.isEnum() || rt1.isArray() ? 1 
>>> : Iterable.class.isAssignableFrom(rt1) ? -1 : 0,
>> 
>> Doesn't this put primitives, enums and arrays at the end instead of at the 
>> start? I've tried this with a simple array:
>> 
>> Class[] types = { int.class, String.class, List.class, long.class, 
>> TimeUnit.class, byte[].class, Integer.class };
>> 
>> The result of sorting:
>> 
>>  Class[7] { interface java.util.List, class java.lang.String, class 
>> java.lang.Integer, int, long, class java.util.concurrent.TimeUnit, class [B }
>> 
>> By switching the -1 and 1 I get the primitives etc.  at the start:
>> 
>>  Class[7] { int, long, class java.util.concurrent.TimeUnit, class [B, class 
>> java.lang.String, class java.lang.Integer, interface java.util.List }
>> ``
>
> The `equalator`s are joined together in reverse order, so this is actually 
> correct for the current implementation:
> 
> 
> record Example(A a, B b, C c) {
>   public static void main(String... args) {
>   final var left  = new Example(new A(), new B(), new C());
>   final var right = new Example(new A(), new B(), new C());
> 
>   left.equals(right);
>   // prints:
>   // > C::equals()
>   // > B::equals()
>   // > A::equals()
>   }
> }
> 
> record A() {
>   @Override
>   public boolean equals(Object other) {
>   System.out.println("A::equals()");
>   return other instanceof A;
>   }
> }
> 
> record B() {
>   @Override
>   public boolean equals(Object other) {
>   System.out.println("B::equals()");
>   return other instanceof B;
>   }
> }
> 
> record C() {
>   @Override
>   public boolean equals(Object other) {
>   System.out.println("C::equals()");
>   return other instanceof C;
>   }
> }

I've added the test case for the current algorithm

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17143#discussion_r1435034161


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals() [v6]

2023-12-22 Thread Sergey Tsypanov
> Currently if we create a record it's fields are compared in their declaration 
> order. This might be ineffective in cases when two objects have "heavy" 
> fields equals to each other, but different "lightweight" fields (heavy and 
> lightweight in terms of comparison) e.g. primitives, enums, 
> nullable/non-nulls etc.
> 
> If we have declared a record like
> 
> public record MyRecord(String field1, int field2) {}
> 
> It's equals() looks like:
> 
>   public final equals(Ljava/lang/Object;)Z
>L0
> LINENUMBER 3 L0
> ALOAD 0
> ALOAD 1
> INVOKEDYNAMIC 
> equals(Lcom/caspianone/openbanking/productservice/controller/MyRecord;Ljava/lang/Object;)Z
>  [
>   // handle kind 0x6 : INVOKESTATIC
>   
> java/lang/runtime/ObjectMethods.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
>   // arguments:
>   com.caspianone.openbanking.productservice.controller.MyRecord.class,
>   "field1;field2",
>   // handle kind 0x1 : GETFIELD
>   
> com/caspianone/openbanking/productservice/controller/MyRecord.field1(Ljava/lang/String;),
>   // handle kind 0x1 : GETFIELD
>   com/caspianone/openbanking/productservice/controller/MyRecord.field2(I)
> ]
> IRETURN
>L1
> LOCALVARIABLE this 
> Lcom/caspianone/openbanking/productservice/controller/MyRecord; L0 L1 0
> LOCALVARIABLE o Ljava/lang/Object; L0 L1 1
> MAXSTACK = 2
> MAXLOCALS = 2
> 
> This can be improved by rearranging the comparison order of the fields moving 
> enums and primitives upper, and collections/arrays lower.

Sergey Tsypanov has updated the pull request incrementally with two additional 
commits since the last revision:

 - Merge remote-tracking branch 'origin/record-equals' into record-equals
 - 8322292: Add test case

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/17143/files
  - new: https://git.openjdk.org/jdk/pull/17143/files/158d9a83..037a3fd1

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=17143=05
 - incr: https://webrevs.openjdk.org/?repo=jdk=17143=04-05

  Stats: 42 lines in 1 file changed: 41 ins; 0 del; 1 mod
  Patch: https://git.openjdk.org/jdk/pull/17143.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/17143/head:pull/17143

PR: https://git.openjdk.org/jdk/pull/17143


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals() [v5]

2023-12-21 Thread ExE Boss
On Thu, 21 Dec 2023 18:30:40 GMT, Rob Spoor  wrote:

>> Sergey Tsypanov has updated the pull request incrementally with one 
>> additional commit since the last revision:
>> 
>>   Update src/java.base/share/classes/java/lang/runtime/ObjectMethods.java
>>   
>>   Co-authored-by: ExE Boss <3889017+exe-b...@users.noreply.github.com>
>
> src/java.base/share/classes/java/lang/runtime/ObjectMethods.java line 224:
> 
>> 222: var rt2 = mh2.type().returnType();
>> 223: return Integer.compare(
>> 224: rt1.isPrimitive() || rt1.isEnum() || rt1.isArray() ? 1 
>> : Iterable.class.isAssignableFrom(rt1) ? -1 : 0,
> 
> Doesn't this put primitives, enums and arrays at the end instead of at the 
> start? I've tried this with a simple array:
> 
> Class[] types = { int.class, String.class, List.class, long.class, 
> TimeUnit.class, byte[].class, Integer.class };
> 
> The result of sorting:
> 
>  Class[7] { interface java.util.List, class java.lang.String, class 
> java.lang.Integer, int, long, class java.util.concurrent.TimeUnit, class [B }
> 
> By switching the -1 and 1 I get the primitives etc.  at the start:
> 
>  Class[7] { int, long, class java.util.concurrent.TimeUnit, class [B, class 
> java.lang.String, class java.lang.Integer, interface java.util.List }
> ``

The `equalator`s are joined together in reverse order, so this is actually 
correct for the current implementation:


record Example(A a, B b, C c) {
public static void main(String... args) {
final var left  = new Example(new A(), new B(), new C());
final var right = new Example(new A(), new B(), new C());

left.equals(right);
// prints:
// > C::equals()
// > B::equals()
// > A::equals()
}
}

record A() {
@Override
public boolean equals(Object other) {
System.out.println("A::equals()");
return other instanceof A;
}
}

record B() {
@Override
public boolean equals(Object other) {
System.out.println("B::equals()");
return other instanceof B;
}
}

record C() {
@Override
public boolean equals(Object other) {
System.out.println("C::equals()");
return other instanceof C;
}
}

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17143#discussion_r1434439484


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals() [v5]

2023-12-21 Thread Rob Spoor
On Thu, 21 Dec 2023 16:58:00 GMT, Sergey Tsypanov  wrote:

>> Currently if we create a record it's fields are compared in their 
>> declaration order. This might be ineffective in cases when two objects have 
>> "heavy" fields equals to each other, but different "lightweight" fields 
>> (heavy and lightweight in terms of comparison) e.g. primitives, enums, 
>> nullable/non-nulls etc.
>> 
>> If we have declared a record like
>> 
>> public record MyRecord(String field1, int field2) {}
>> 
>> It's equals() looks like:
>> 
>>   public final equals(Ljava/lang/Object;)Z
>>L0
>> LINENUMBER 3 L0
>> ALOAD 0
>> ALOAD 1
>> INVOKEDYNAMIC 
>> equals(Lcom/caspianone/openbanking/productservice/controller/MyRecord;Ljava/lang/Object;)Z
>>  [
>>   // handle kind 0x6 : INVOKESTATIC
>>   
>> java/lang/runtime/ObjectMethods.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
>>   // arguments:
>>   com.caspianone.openbanking.productservice.controller.MyRecord.class,
>>   "field1;field2",
>>   // handle kind 0x1 : GETFIELD
>>   
>> com/caspianone/openbanking/productservice/controller/MyRecord.field1(Ljava/lang/String;),
>>   // handle kind 0x1 : GETFIELD
>>   com/caspianone/openbanking/productservice/controller/MyRecord.field2(I)
>> ]
>> IRETURN
>>L1
>> LOCALVARIABLE this 
>> Lcom/caspianone/openbanking/productservice/controller/MyRecord; L0 L1 0
>> LOCALVARIABLE o Ljava/lang/Object; L0 L1 1
>> MAXSTACK = 2
>> MAXLOCALS = 2
>> 
>> This can be improved by rearranging the comparison order of the fields 
>> moving enums and primitives upper, and collections/arrays lower.
>
> Sergey Tsypanov has updated the pull request incrementally with one 
> additional commit since the last revision:
> 
>   Update src/java.base/share/classes/java/lang/runtime/ObjectMethods.java
>   
>   Co-authored-by: ExE Boss <3889017+exe-b...@users.noreply.github.com>

src/java.base/share/classes/java/lang/runtime/ObjectMethods.java line 224:

> 222: var rt2 = mh2.type().returnType();
> 223: return Integer.compare(
> 224: rt1.isPrimitive() || rt1.isEnum() || rt1.isArray() ? 1 : 
> Iterable.class.isAssignableFrom(rt1) ? -1 : 0,

Doesn't this put primitives, enums and arrays at the end instead of at the 
start? I've tried this with a simple array:

Class[] types = { int.class, String.class, List.class, long.class, 
TimeUnit.class, byte[].class, Integer.class };

The result of sorting:

 Class[7] { interface java.util.List, class java.lang.String, class 
java.lang.Integer, int, long, class java.util.concurrent.TimeUnit, class [B }

By switching the -1 and 1 I get the primitives etc.  at the start:

 Class[7] { int, long, class java.util.concurrent.TimeUnit, class [B, class 
java.lang.String, class java.lang.Integer, interface java.util.List }
``

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17143#discussion_r1434386929


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals() [v5]

2023-12-21 Thread Sergey Tsypanov
> Currently if we create a record it's fields are compared in their declaration 
> order. This might be ineffective in cases when two objects have "heavy" 
> fields equals to each other, but different "lightweight" fields (heavy and 
> lightweight in terms of comparison) e.g. primitives, enums, 
> nullable/non-nulls etc.
> 
> If we have declared a record like
> 
> public record MyRecord(String field1, int field2) {}
> 
> It's equals() looks like:
> 
>   public final equals(Ljava/lang/Object;)Z
>L0
> LINENUMBER 3 L0
> ALOAD 0
> ALOAD 1
> INVOKEDYNAMIC 
> equals(Lcom/caspianone/openbanking/productservice/controller/MyRecord;Ljava/lang/Object;)Z
>  [
>   // handle kind 0x6 : INVOKESTATIC
>   
> java/lang/runtime/ObjectMethods.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
>   // arguments:
>   com.caspianone.openbanking.productservice.controller.MyRecord.class,
>   "field1;field2",
>   // handle kind 0x1 : GETFIELD
>   
> com/caspianone/openbanking/productservice/controller/MyRecord.field1(Ljava/lang/String;),
>   // handle kind 0x1 : GETFIELD
>   com/caspianone/openbanking/productservice/controller/MyRecord.field2(I)
> ]
> IRETURN
>L1
> LOCALVARIABLE this 
> Lcom/caspianone/openbanking/productservice/controller/MyRecord; L0 L1 0
> LOCALVARIABLE o Ljava/lang/Object; L0 L1 1
> MAXSTACK = 2
> MAXLOCALS = 2
> 
> This can be improved by rearranging the comparison order of the fields moving 
> enums and primitives upper, and collections/arrays lower.

Sergey Tsypanov has updated the pull request incrementally with one additional 
commit since the last revision:

  Update src/java.base/share/classes/java/lang/runtime/ObjectMethods.java
  
  Co-authored-by: ExE Boss <3889017+exe-b...@users.noreply.github.com>

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/17143/files
  - new: https://git.openjdk.org/jdk/pull/17143/files/9c8ae4fb..158d9a83

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=17143=04
 - incr: https://webrevs.openjdk.org/?repo=jdk=17143=03-04

  Stats: 4 lines in 1 file changed: 0 ins; 0 del; 4 mod
  Patch: https://git.openjdk.org/jdk/pull/17143.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/17143/head:pull/17143

PR: https://git.openjdk.org/jdk/pull/17143


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals() [v4]

2023-12-21 Thread ExE Boss
On Thu, 21 Dec 2023 14:47:43 GMT, ExE Boss  wrote:

>> Sergey Tsypanov has updated the pull request incrementally with one 
>> additional commit since the last revision:
>> 
>>   8322292: Tiny improvement
>
> src/java.base/share/classes/java/lang/runtime/ObjectMethods.java line 227:
> 
>> 225: }
>> 226: return rt1.isPrimitive() || rt1.isEnum() || rt1.isArray() ? 
>> 1 : Iterable.class.isAssignableFrom(rt1) ? -1 : 0;
>> 227: });
> 
> The way this comparator is currently implemented, the `signum(c.compare(mh1, 
> mh2)) == -signum(c.compare(mh2, mh1))` assertion won’t hold, which will cause 
> the sorting to be unstable.

This should ensure stable ordering:
Suggestion:

Arrays.sort(equalsGetters, (mh1, mh2) -> {
var rt1 = mh1.type().returnType();
var rt2 = mh2.type().returnType();
return Integer.compare(
rt1.isPrimitive() || rt1.isEnum() || rt1.isArray() ? 1 : 
Iterable.class.isAssignableFrom(rt1) ? -1 : 0,
rt2.isPrimitive() || rt2.isEnum() || rt2.isArray() ? 1 : 
Iterable.class.isAssignableFrom(rt2) ? -1 : 0
);
});

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17143#discussion_r1434173126


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals() [v4]

2023-12-21 Thread ExE Boss
On Wed, 20 Dec 2023 10:11:58 GMT, Sergey Tsypanov  wrote:

>> Currently if we create a record it's fields are compared in their 
>> declaration order. This might be ineffective in cases when two objects have 
>> "heavy" fields equals to each other, but different "lightweight" fields 
>> (heavy and lightweight in terms of comparison) e.g. primitives, enums, 
>> nullable/non-nulls etc.
>> 
>> If we have declared a record like
>> 
>> public record MyRecord(String field1, int field2) {}
>> 
>> It's equals() looks like:
>> 
>>   public final equals(Ljava/lang/Object;)Z
>>L0
>> LINENUMBER 3 L0
>> ALOAD 0
>> ALOAD 1
>> INVOKEDYNAMIC 
>> equals(Lcom/caspianone/openbanking/productservice/controller/MyRecord;Ljava/lang/Object;)Z
>>  [
>>   // handle kind 0x6 : INVOKESTATIC
>>   
>> java/lang/runtime/ObjectMethods.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
>>   // arguments:
>>   com.caspianone.openbanking.productservice.controller.MyRecord.class,
>>   "field1;field2",
>>   // handle kind 0x1 : GETFIELD
>>   
>> com/caspianone/openbanking/productservice/controller/MyRecord.field1(Ljava/lang/String;),
>>   // handle kind 0x1 : GETFIELD
>>   com/caspianone/openbanking/productservice/controller/MyRecord.field2(I)
>> ]
>> IRETURN
>>L1
>> LOCALVARIABLE this 
>> Lcom/caspianone/openbanking/productservice/controller/MyRecord; L0 L1 0
>> LOCALVARIABLE o Ljava/lang/Object; L0 L1 1
>> MAXSTACK = 2
>> MAXLOCALS = 2
>> 
>> This can be improved by rearranging the comparison order of the fields 
>> moving enums and primitives upper, and collections/arrays lower.
>
> Sergey Tsypanov has updated the pull request incrementally with one 
> additional commit since the last revision:
> 
>   8322292: Tiny improvement

src/java.base/share/classes/java/lang/runtime/ObjectMethods.java line 227:

> 225: }
> 226: return rt1.isPrimitive() || rt1.isEnum() || rt1.isArray() ? 
> 1 : Iterable.class.isAssignableFrom(rt1) ? -1 : 0;
> 227: });

The way this comparator is currently implemented, the `signum(c.compare(mh1, 
mh2)) == -signum(c.compare(mh2, mh1))` assertion won’t hold, which will cause 
the sorting to be unstable.

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17143#discussion_r1434166820


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals() [v4]

2023-12-20 Thread Sergey Tsypanov
> Currently if we create a record it's fields are compared in their declaration 
> order. This might be ineffective in cases when two objects have "heavy" 
> fields equals to each other, but different "lightweight" fields (heavy and 
> lightweight in terms of comparison) e.g. primitives, enums, 
> nullable/non-nulls etc.
> 
> If we have declared a record like
> 
> public record MyRecord(String field1, int field2) {}
> 
> It's equals() looks like:
> 
>   public final equals(Ljava/lang/Object;)Z
>L0
> LINENUMBER 3 L0
> ALOAD 0
> ALOAD 1
> INVOKEDYNAMIC 
> equals(Lcom/caspianone/openbanking/productservice/controller/MyRecord;Ljava/lang/Object;)Z
>  [
>   // handle kind 0x6 : INVOKESTATIC
>   
> java/lang/runtime/ObjectMethods.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
>   // arguments:
>   com.caspianone.openbanking.productservice.controller.MyRecord.class,
>   "field1;field2",
>   // handle kind 0x1 : GETFIELD
>   
> com/caspianone/openbanking/productservice/controller/MyRecord.field1(Ljava/lang/String;),
>   // handle kind 0x1 : GETFIELD
>   com/caspianone/openbanking/productservice/controller/MyRecord.field2(I)
> ]
> IRETURN
>L1
> LOCALVARIABLE this 
> Lcom/caspianone/openbanking/productservice/controller/MyRecord; L0 L1 0
> LOCALVARIABLE o Ljava/lang/Object; L0 L1 1
> MAXSTACK = 2
> MAXLOCALS = 2
> 
> This can be improved by rearranging the comparison order of the fields moving 
> enums and primitives upper, and collections/arrays lower.

Sergey Tsypanov has updated the pull request incrementally with one additional 
commit since the last revision:

  8322292: Tiny improvement

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/17143/files
  - new: https://git.openjdk.org/jdk/pull/17143/files/dded977f..9c8ae4fb

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=17143=03
 - incr: https://webrevs.openjdk.org/?repo=jdk=17143=02-03

  Stats: 2 lines in 1 file changed: 0 ins; 0 del; 2 mod
  Patch: https://git.openjdk.org/jdk/pull/17143.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/17143/head:pull/17143

PR: https://git.openjdk.org/jdk/pull/17143


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals()

2023-12-19 Thread Rémi Forax
On Tue, 19 Dec 2023 11:01:12 GMT, Hannes Greule  wrote:

> Isn't Arrays.equals() used under the hood?
No, for arrays == is used

-

PR Comment: https://git.openjdk.org/jdk/pull/17143#issuecomment-1863374656


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals() [v3]

2023-12-19 Thread Sergey Tsypanov
> Currently if we create a record it's fields are compared in their declaration 
> order. This might be ineffective in cases when two objects have "heavy" 
> fields equals to each other, but different "lightweight" fields (heavy and 
> lightweight in terms of comparison) e.g. primitives, enums, 
> nullable/non-nulls etc.
> 
> If we have declared a record like
> 
> public record MyRecord(String field1, int field2) {}
> 
> It's equals() looks like:
> 
>   public final equals(Ljava/lang/Object;)Z
>L0
> LINENUMBER 3 L0
> ALOAD 0
> ALOAD 1
> INVOKEDYNAMIC 
> equals(Lcom/caspianone/openbanking/productservice/controller/MyRecord;Ljava/lang/Object;)Z
>  [
>   // handle kind 0x6 : INVOKESTATIC
>   
> java/lang/runtime/ObjectMethods.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
>   // arguments:
>   com.caspianone.openbanking.productservice.controller.MyRecord.class,
>   "field1;field2",
>   // handle kind 0x1 : GETFIELD
>   
> com/caspianone/openbanking/productservice/controller/MyRecord.field1(Ljava/lang/String;),
>   // handle kind 0x1 : GETFIELD
>   com/caspianone/openbanking/productservice/controller/MyRecord.field2(I)
> ]
> IRETURN
>L1
> LOCALVARIABLE this 
> Lcom/caspianone/openbanking/productservice/controller/MyRecord; L0 L1 0
> LOCALVARIABLE o Ljava/lang/Object; L0 L1 1
> MAXSTACK = 2
> MAXLOCALS = 2
> 
> This can be improved by rearranging the comparison order of the fields moving 
> enums and primitives upper, and collections/arrays lower.

Sergey Tsypanov has updated the pull request incrementally with one additional 
commit since the last revision:

  8322292: Shift arrays up

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/17143/files
  - new: https://git.openjdk.org/jdk/pull/17143/files/988601b3..dded977f

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=17143=02
 - incr: https://webrevs.openjdk.org/?repo=jdk=17143=01-02

  Stats: 1 line in 1 file changed: 0 ins; 0 del; 1 mod
  Patch: https://git.openjdk.org/jdk/pull/17143.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/17143/head:pull/17143

PR: https://git.openjdk.org/jdk/pull/17143


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals()

2023-12-19 Thread Hannes Greule
On Tue, 19 Dec 2023 09:41:45 GMT, Sergey Tsypanov  wrote:

> Isn't `Arrays.equals()` used under the hood?

The JLS and the API spec don't mention any special-casing of arrays, and the 
code seems to use `Objects.equals` for all non-primitive types: 
https://github.com/openjdk/jdk/blob/988601b324c971daf4e537074a007c25059af91b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java#L183-L187

(side note, it seems like `OBJECT_EQUALS` is unused?)

-

PR Comment: https://git.openjdk.org/jdk/pull/17143#issuecomment-1862550269


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals() [v2]

2023-12-19 Thread Sergey Tsypanov
> Currently if we create a record it's fields are compared in their declaration 
> order. This might be ineffective in cases when two objects have "heavy" 
> fields equals to each other, but different "lightweight" fields (heavy and 
> lightweight in terms of comparison) e.g. primitives, enums, 
> nullable/non-nulls etc.
> 
> If we have declared a record like
> 
> public record MyRecord(String field1, int field2) {}
> 
> It's equals() looks like:
> 
>   public final equals(Ljava/lang/Object;)Z
>L0
> LINENUMBER 3 L0
> ALOAD 0
> ALOAD 1
> INVOKEDYNAMIC 
> equals(Lcom/caspianone/openbanking/productservice/controller/MyRecord;Ljava/lang/Object;)Z
>  [
>   // handle kind 0x6 : INVOKESTATIC
>   
> java/lang/runtime/ObjectMethods.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
>   // arguments:
>   com.caspianone.openbanking.productservice.controller.MyRecord.class,
>   "field1;field2",
>   // handle kind 0x1 : GETFIELD
>   
> com/caspianone/openbanking/productservice/controller/MyRecord.field1(Ljava/lang/String;),
>   // handle kind 0x1 : GETFIELD
>   com/caspianone/openbanking/productservice/controller/MyRecord.field2(I)
> ]
> IRETURN
>L1
> LOCALVARIABLE this 
> Lcom/caspianone/openbanking/productservice/controller/MyRecord; L0 L1 0
> LOCALVARIABLE o Ljava/lang/Object; L0 L1 1
> MAXSTACK = 2
> MAXLOCALS = 2
> 
> This can be improved by rearranging the comparison order of the fields moving 
> enums and primitives upper, and collections/arrays lower.

Sergey Tsypanov has updated the pull request incrementally with one additional 
commit since the last revision:

  8322292: Use copy

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/17143/files
  - new: https://git.openjdk.org/jdk/pull/17143/files/26c4428c..988601b3

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk=17143=01
 - incr: https://webrevs.openjdk.org/?repo=jdk=17143=00-01

  Stats: 4 lines in 1 file changed: 1 ins; 0 del; 3 mod
  Patch: https://git.openjdk.org/jdk/pull/17143.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/17143/head:pull/17143

PR: https://git.openjdk.org/jdk/pull/17143


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals()

2023-12-19 Thread Sergey Tsypanov
On Tue, 19 Dec 2023 06:07:31 GMT, Hannes Greule  wrote:

> Arrays are compared by reference

Isn't `Arrays.equals()` used under the hood?

> You are sorting the array passed to the bootstrap method

Good point, fixed.

-

PR Comment: https://git.openjdk.org/jdk/pull/17143#issuecomment-1862429275


Re: RFR: 8322292: Rearrange comparison of fields in Record.equals()

2023-12-18 Thread Hannes Greule
On Mon, 18 Dec 2023 13:42:35 GMT, Sergey Tsypanov  wrote:

> Currently if we create a record it's fields are compared in their declaration 
> order. This might be ineffective in cases when two objects have "heavy" 
> fields equals to each other, but different "lightweight" fields (heavy and 
> lightweight in terms of comparison) e.g. primitives, enums, 
> nullable/non-nulls etc.
> 
> If we have declared a record like
> 
> public record MyRecord(String field1, int field2) {}
> 
> It's equals() looks like:
> 
>   public final equals(Ljava/lang/Object;)Z
>L0
> LINENUMBER 3 L0
> ALOAD 0
> ALOAD 1
> INVOKEDYNAMIC 
> equals(Lcom/caspianone/openbanking/productservice/controller/MyRecord;Ljava/lang/Object;)Z
>  [
>   // handle kind 0x6 : INVOKESTATIC
>   
> java/lang/runtime/ObjectMethods.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
>   // arguments:
>   com.caspianone.openbanking.productservice.controller.MyRecord.class,
>   "field1;field2",
>   // handle kind 0x1 : GETFIELD
>   
> com/caspianone/openbanking/productservice/controller/MyRecord.field1(Ljava/lang/String;),
>   // handle kind 0x1 : GETFIELD
>   com/caspianone/openbanking/productservice/controller/MyRecord.field2(I)
> ]
> IRETURN
>L1
> LOCALVARIABLE this 
> Lcom/caspianone/openbanking/productservice/controller/MyRecord; L0 L1 0
> LOCALVARIABLE o Ljava/lang/Object; L0 L1 1
> MAXSTACK = 2
> MAXLOCALS = 2
> 
> This can be improved by rearranging the comparison order of the fields moving 
> enums and primitives upper, and collections/arrays lower.

Generally, this is a good idea. A few comments:

1. Arrays are compared by reference rather than element-wise, so they 
should/could be at the beginning similar to enums, not at the end.
2. You are sorting the array passed to the bootstrap method. This might be 
observable to callers, potentially causing problems, especially when e.g. 
creating the method handle for equals first, and then for toString with the 
same array.
3. What's the test situation here? Is there enough coverage for things like 
that already?

-

PR Comment: https://git.openjdk.org/jdk/pull/17143#issuecomment-1862179369


RFR: 8322292: Rearrange comparison of fields in Record.equals()

2023-12-18 Thread Sergey Tsypanov
Currently if we create a record it's fields are compared in their declaration 
order. This might be ineffective in cases when two objects have "heavy" fields 
equals to each other, but different "lightweight" fields (heavy and lightweight 
in terms of comparison) e.g. primitives, enums, nullable/non-nulls etc.

If we have declared a record like

public record MyRecord(String field1, int field2) {}

It's equals() looks like:

  public final equals(Ljava/lang/Object;)Z
   L0
LINENUMBER 3 L0
ALOAD 0
ALOAD 1
INVOKEDYNAMIC 
equals(Lcom/caspianone/openbanking/productservice/controller/MyRecord;Ljava/lang/Object;)Z
 [
  // handle kind 0x6 : INVOKESTATIC
  
java/lang/runtime/ObjectMethods.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
  // arguments:
  com.caspianone.openbanking.productservice.controller.MyRecord.class,
  "field1;field2",
  // handle kind 0x1 : GETFIELD
  
com/caspianone/openbanking/productservice/controller/MyRecord.field1(Ljava/lang/String;),
  // handle kind 0x1 : GETFIELD
  com/caspianone/openbanking/productservice/controller/MyRecord.field2(I)
]
IRETURN
   L1
LOCALVARIABLE this 
Lcom/caspianone/openbanking/productservice/controller/MyRecord; L0 L1 0
LOCALVARIABLE o Ljava/lang/Object; L0 L1 1
MAXSTACK = 2
MAXLOCALS = 2

This can be improved by rearranging the comparison order of the fields moving 
enums and primitives upper, and collections/arrays lower.

-

Commit messages:
 - 8322292: Update copyright
 - 8322292: Shift arrays and Iterables down
 - Improve Record.equals()

Changes: https://git.openjdk.org/jdk/pull/17143/files
 Webrev: https://webrevs.openjdk.org/?repo=jdk=17143=00
  Issue: https://bugs.openjdk.org/browse/JDK-8322292
  Stats: 12 lines in 1 file changed: 9 ins; 0 del; 3 mod
  Patch: https://git.openjdk.org/jdk/pull/17143.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/17143/head:pull/17143

PR: https://git.openjdk.org/jdk/pull/17143