summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java110
-rw-r--r--src/main/java/com/amazon/carbonado/gen/StorableGenerator.java103
2 files changed, 114 insertions, 99 deletions
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
@@ -365,6 +365,116 @@ public class CodeBuilderUtil {
}
/**
+ * 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<S extends Storable> {
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.
*