From 8d5c1796c151375ac8978ded048514bdc8922c1e Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Fri, 12 Mar 2010 02:40:14 +0000 Subject: Refactored hashcode generating code to utility method. --- .../com/amazon/carbonado/gen/CodeBuilderUtil.java | 110 +++++++++++++++++++++ .../amazon/carbonado/gen/StorableGenerator.java | 103 +------------------ 2 files changed, 114 insertions(+), 99 deletions(-) (limited to 'src/main/java/com/amazon/carbonado') diff --git a/src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java b/src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java index f35024e..280e3fd 100644 --- a/src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java +++ b/src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java @@ -364,6 +364,116 @@ public class CodeBuilderUtil { return cf; } + /** + * Generates code to compute a hashcode for a value on the stack, consuming + * the value. After the code executes, the stack contains an int hashcode. + * + * @param b {@link CodeBuilder} to which to add the code + * @param valueType the type of the value + * @param testForNull if true and the value is a reference and might be null + * @param mixIn if true, stack has an existing hashcode followed by a value + * @since 1.2.2 + */ + public static void addValueHashCodeCall(CodeBuilder b, + TypeDesc valueType, + boolean testForNull, + boolean mixIn) + { + LocalVariable value = null; + if (mixIn) { + value = b.createLocalVariable(null, valueType); + b.storeLocal(value); + + // Multiply current hashcode by 31 before adding more to it. + b.loadConstant(31); + b.math(Opcode.IMUL); + + b.loadLocal(value); + } + + switch (valueType.getTypeCode()) { + case TypeDesc.FLOAT_CODE: + b.invokeStatic(TypeDesc.FLOAT.toObjectType(), "floatToIntBits", + TypeDesc.INT, new TypeDesc[]{TypeDesc.FLOAT}); + // Fall through + case TypeDesc.INT_CODE: + case TypeDesc.CHAR_CODE: + case TypeDesc.SHORT_CODE: + case TypeDesc.BYTE_CODE: + case TypeDesc.BOOLEAN_CODE: + if (mixIn) { + b.math(Opcode.IADD); + } + break; + + case TypeDesc.DOUBLE_CODE: + b.invokeStatic(TypeDesc.DOUBLE.toObjectType(), "doubleToLongBits", + TypeDesc.LONG, new TypeDesc[]{TypeDesc.DOUBLE}); + // Fall through + case TypeDesc.LONG_CODE: + b.dup2(); + b.loadConstant(32); + b.math(Opcode.LUSHR); + b.math(Opcode.LXOR); + b.convert(TypeDesc.LONG, TypeDesc.INT); + if (mixIn) { + b.math(Opcode.IADD); + } + break; + + case TypeDesc.OBJECT_CODE: + default: + if (testForNull) { + if (value == null) { + value = b.createLocalVariable(null, valueType); + b.storeLocal(value); + b.loadLocal(value); + } + } + if (mixIn) { + Label isNull = b.createLabel(); + if (testForNull) { + b.ifNullBranch(isNull, true); + b.loadLocal(value); + } + addValueHashCodeCallTo(b, valueType); + b.math(Opcode.IADD); + if (testForNull) { + isNull.setLocation(); + } + } else { + Label cont = b.createLabel(); + if (testForNull) { + Label notNull = b.createLabel(); + b.ifNullBranch(notNull, false); + b.loadConstant(0); + b.branch(cont); + notNull.setLocation(); + b.loadLocal(value); + } + addValueHashCodeCallTo(b, valueType); + if (testForNull) { + cont.setLocation(); + } + } + break; + } + } + + private static void addValueHashCodeCallTo(CodeBuilder b, TypeDesc valueType) { + if (valueType.isArray()) { + if (!valueType.getComponentType().isPrimitive()) { + b.invokeStatic("java.util.Arrays", "deepHashCode", + TypeDesc.INT, new TypeDesc[] {TypeDesc.forClass(Object[].class)}); + } else { + b.invokeStatic("java.util.Arrays", "hashCode", + TypeDesc.INT, new TypeDesc[] {valueType}); + } + } else { + b.invokeVirtual(TypeDesc.OBJECT, "hashCode", TypeDesc.INT, null); + } + } + /** * Generates code to compare a field in this object against the same one in a * different instance. Branch to the provided Label if they are not equal. diff --git a/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java b/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java index 6fd19fc..7604325 100644 --- a/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java +++ b/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java @@ -3018,111 +3018,16 @@ public final class StorableGenerator { if (property.isDerived() || property.isJoin()) { continue; } - addHashCodeCall(b, property.getName(), - TypeDesc.forClass(property.getType()), true, mixIn); + TypeDesc fieldType = TypeDesc.forClass(property.getType()); + b.loadThis(); + b.loadField(property.getName(), fieldType); + CodeBuilderUtil.addValueHashCodeCall(b, fieldType, true, mixIn); mixIn = true; } b.returnValue(TypeDesc.INT); } - private void addHashCodeCall(CodeBuilder b, String fieldName, - TypeDesc fieldType, boolean testForNull, - boolean mixIn) - { - if (mixIn) { - // Multiply current hashcode by 31 before adding more to it. - b.loadConstant(5); - b.math(Opcode.ISHL); - b.loadConstant(1); - b.math(Opcode.ISUB); - } - - b.loadThis(); - b.loadField(fieldName, fieldType); - - switch (fieldType.getTypeCode()) { - case TypeDesc.FLOAT_CODE: - b.invokeStatic(TypeDesc.FLOAT.toObjectType(), "floatToIntBits", - TypeDesc.INT, new TypeDesc[]{TypeDesc.FLOAT}); - // Fall through - case TypeDesc.INT_CODE: - case TypeDesc.CHAR_CODE: - case TypeDesc.SHORT_CODE: - case TypeDesc.BYTE_CODE: - case TypeDesc.BOOLEAN_CODE: - if (mixIn) { - b.math(Opcode.IADD); - } - break; - - case TypeDesc.DOUBLE_CODE: - b.invokeStatic(TypeDesc.DOUBLE.toObjectType(), "doubleToLongBits", - TypeDesc.LONG, new TypeDesc[]{TypeDesc.DOUBLE}); - // Fall through - case TypeDesc.LONG_CODE: - b.dup2(); - b.loadConstant(32); - b.math(Opcode.LUSHR); - b.math(Opcode.LXOR); - b.convert(TypeDesc.LONG, TypeDesc.INT); - if (mixIn) { - b.math(Opcode.IADD); - } - break; - - case TypeDesc.OBJECT_CODE: - default: - LocalVariable value = null; - if (testForNull) { - value = b.createLocalVariable(null, fieldType); - b.storeLocal(value); - b.loadLocal(value); - } - if (mixIn) { - Label isNull = b.createLabel(); - if (testForNull) { - b.ifNullBranch(isNull, true); - b.loadLocal(value); - } - addHashCodeCallTo(b, fieldType); - b.math(Opcode.IADD); - if (testForNull) { - isNull.setLocation(); - } - } else { - Label cont = b.createLabel(); - if (testForNull) { - Label notNull = b.createLabel(); - b.ifNullBranch(notNull, false); - b.loadConstant(0); - b.branch(cont); - notNull.setLocation(); - b.loadLocal(value); - } - addHashCodeCallTo(b, fieldType); - if (testForNull) { - cont.setLocation(); - } - } - break; - } - } - - private void addHashCodeCallTo(CodeBuilder b, TypeDesc fieldType) { - if (fieldType.isArray()) { - if (!fieldType.getComponentType().isPrimitive()) { - b.invokeStatic("java.util.Arrays", "deepHashCode", - TypeDesc.INT, new TypeDesc[] {TypeDesc.forClass(Object[].class)}); - } else { - b.invokeStatic("java.util.Arrays", "hashCode", - TypeDesc.INT, new TypeDesc[] {fieldType}); - } - } else { - b.invokeVirtual(TypeDesc.OBJECT, "hashCode", TypeDesc.INT, null); - } - } - /** * Defines an equals method. * -- cgit v1.2.3