From e3008d8dbf90112a40a5dee24f961c4b84c9436a Mon Sep 17 00:00:00 2001 From: Werner Dietl Date: Mon, 20 Apr 2026 21:27:03 -0400 Subject: [PATCH] Cache the hashCode for dataflow expressions --- .../dataflow/expression/ArrayAccess.java | 8 +++++++- .../dataflow/expression/ArrayCreation.java | 8 +++++++- .../dataflow/expression/BinaryOperation.java | 8 +++++++- .../dataflow/expression/FieldAccess.java | 8 +++++++- .../dataflow/expression/FormalParameter.java | 19 +++++++++++++------ .../dataflow/expression/LocalVariable.java | 10 ++++++++-- .../dataflow/expression/MethodCall.java | 15 +++++++++++---- .../dataflow/expression/UnaryOperation.java | 8 +++++++- .../dataflow/expression/ValueLiteral.java | 8 +++++++- 9 files changed, 74 insertions(+), 18 deletions(-) diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayAccess.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayAccess.java index 94915ee6379d..fb07393f0854 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayAccess.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayAccess.java @@ -104,9 +104,15 @@ public boolean equals(@Nullable Object obj) { return array.equals(other.array) && index.equals(other.index); } + /** Cache the hashCode. Recomputed if zero. */ + private int hashCodeCache = 0; + @Override public int hashCode() { - return Objects.hash(array, index); + if (hashCodeCache == 0) { + hashCodeCache = Objects.hash(array, index); + } + return hashCodeCache; } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayCreation.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayCreation.java index f41351ae762d..ce3c8101b7a4 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayCreation.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayCreation.java @@ -88,9 +88,15 @@ public boolean isModifiableByOtherCode() { return true; } + /** Cache the hashCode. Recomputed if zero. */ + private int hashCodeCache = 0; + @Override public int hashCode() { - return Objects.hash(dimensions, initializers, getType().toString()); + if (hashCodeCache == 0) { + hashCodeCache = Objects.hash(dimensions, initializers, getType().toString()); + } + return hashCodeCache; } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/BinaryOperation.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/BinaryOperation.java index a0287c16cf1b..a1b406a2d879 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/BinaryOperation.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/BinaryOperation.java @@ -130,9 +130,15 @@ public boolean containsModifiableAliasOf(Store store, JavaExpression other) { || right.containsModifiableAliasOf(store, other); } + /** Cache the hashCode. Recomputed if zero. */ + private int hashCodeCache = 0; + @Override public int hashCode() { - return Objects.hash(operationKind, left, right); + if (hashCodeCache == 0) { + hashCodeCache = Objects.hash(operationKind, left, right); + } + return hashCodeCache; } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/FieldAccess.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/FieldAccess.java index 566c13e494b3..75a5e932a47c 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/FieldAccess.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/FieldAccess.java @@ -117,9 +117,15 @@ public boolean equals(@Nullable Object obj) { || this.getReceiver() instanceof ThisReference); } + /** Cache the hashCode. Recomputed if zero. */ + private int hashCodeCache = 0; + @Override public int hashCode() { - return Objects.hash(getField(), getReceiver()); + if (hashCodeCache == 0) { + hashCodeCache = Objects.hash(getField(), getReceiver()); + } + return hashCodeCache; } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/FormalParameter.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/FormalParameter.java index 3783545fa174..86167a857e76 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/FormalParameter.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/FormalParameter.java @@ -64,14 +64,21 @@ public VariableElement getElement() { return element; } + /** Cache the hashCode. Recomputed if zero. */ + private int hashCodeCache = 0; + @Override public int hashCode() { - VarSymbol vs = (VarSymbol) element; - return Objects.hash( - index, - vs.name.toString(), - TypeAnnotationUtils.unannotatedType(vs.type).toString(), - vs.owner.toString()); + if (hashCodeCache == 0) { + VarSymbol vs = (VarSymbol) element; + hashCodeCache = + Objects.hash( + index, + vs.name.toString(), + TypeAnnotationUtils.unannotatedType(vs.type).toString(), + vs.owner.toString()); + } + return hashCodeCache; } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/LocalVariable.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/LocalVariable.java index 6d6b3ac110fe..08ed9392b30d 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/LocalVariable.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/LocalVariable.java @@ -79,10 +79,16 @@ public VariableElement getElement() { return element; } + /** Cache the hashCode. Recomputed if zero. */ + private int hashCodeCache = 0; + @Override public int hashCode() { - VarSymbol vs = (VarSymbol) element; - return Objects.hash(vs.pos, vs.name, vs.owner); + if (hashCodeCache == 0) { + VarSymbol vs = (VarSymbol) element; + hashCodeCache = Objects.hash(vs.pos, vs.name, vs.owner); + } + return hashCodeCache; } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/MethodCall.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/MethodCall.java index 98a5ee5f3e2e..5f5f9000121b 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/MethodCall.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/MethodCall.java @@ -167,13 +167,20 @@ public boolean equals(@Nullable Object obj) { && arguments.equals(other.arguments); } + /** Cache the hashCode. Recomputed if zero. */ + private int hashCodeCache = 0; + @Override public int hashCode() { - if (method.getKind() == ElementKind.CONSTRUCTOR) { - // No two constructor instances have the same hashcode. - return System.identityHashCode(this); + if (hashCodeCache == 0) { + if (method.getKind() == ElementKind.CONSTRUCTOR) { + // No two constructor instances have the same hashcode. + hashCodeCache = System.identityHashCode(this); + } else { + hashCodeCache = Objects.hash(method, receiver, arguments); + } } - return Objects.hash(method, receiver, arguments); + return hashCodeCache; } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/UnaryOperation.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/UnaryOperation.java index 9edc157f0b88..3518eac80759 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/UnaryOperation.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/UnaryOperation.java @@ -105,9 +105,15 @@ public boolean containsModifiableAliasOf(Store store, JavaExpression other) { return operand.containsModifiableAliasOf(store, other); } + /** Cache the hashCode. Recomputed if zero. */ + private int hashCodeCache = 0; + @Override public int hashCode() { - return Objects.hash(operationKind, operand); + if (hashCodeCache == 0) { + hashCodeCache = Objects.hash(operationKind, operand); + } + return hashCodeCache; } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ValueLiteral.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ValueLiteral.java index 8f1ada9276e6..6e3a3a977839 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ValueLiteral.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ValueLiteral.java @@ -163,9 +163,15 @@ public String toString() { return value == null ? "null" : value.toString(); } + /** Cache the hashCode. Recomputed if zero. */ + private int hashCodeCache = 0; + @Override public int hashCode() { - return Objects.hash(value, type.toString()); + if (hashCodeCache == 0) { + hashCodeCache = Objects.hash(value, type.toString()); + } + return hashCodeCache; } @Override