classBuilder.addField(fieldModifiers, fieldNamePrefix+i, types[i]);
// Create constructor
- MethodBuilderBase mb = classBuilder.addConstructor(
+ MethodBuilderBase mb = classBuilder.addConstructorBase(
types.length == 0 ? Opcodes.ACC_PRIVATE : Opcodes.ACC_PUBLIC,
JavaTypeTranslator.filterVoid(types));
mb.loadThis();
tsmb.finish();
}
- if(generateEqualsAndHashCode) {
- // Create equals
- {
- TypeDesc CLASS = TypeDesc.forClass(Class.class);
+ if(generateEqualsAndHashCode)
+ implementHashCodeAndEquals(classBuilder, recordName, fieldNamePrefix, types);
+ }
- MethodBuilderBase tsmb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "equals", TypeDesc.BOOLEAN, Constants.OBJECTS[1]);
- LocalVariable parameter = tsmb.getParameter(0);
- Label success = tsmb.createLabel();
- Label failure = tsmb.createLabel();
+ public static void implementHashCodeAndEquals(ClassBuilder classBuilder, String recordName, String fieldNamePrefix, TypeDesc[] types) {
+ // Create equals
+ {
+ TypeDesc CLASS = TypeDesc.forClass(Class.class);
- // Check type
- tsmb.loadThis();
- tsmb.loadLocal(parameter);
- tsmb.ifComparisonBranch(success, "==", TypeDesc.OBJECT);
- tsmb.loadLocal(parameter);
- tsmb.ifNullBranch(failure, true);
- tsmb.loadLocal(parameter);
- tsmb.invokeVirtual("java/lang/Object", "getClass", CLASS, Constants.EMPTY_TYPEDESC_ARRAY);
- tsmb.loadThis();
- tsmb.invokeVirtual("java/lang/Object", "getClass", CLASS, Constants.EMPTY_TYPEDESC_ARRAY);
- tsmb.ifComparisonBranch(failure, "!=", CLASS);
- tsmb.loadLocal(parameter);
- tsmb.checkCast(classBuilder.getType());
- LocalVariable other = tsmb.createLocalVariable("other", classBuilder.getType());
- tsmb.storeLocal(other);
+ MethodBuilderBase tsmb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "equals", TypeDesc.BOOLEAN, Constants.OBJECTS[1]);
+ LocalVariable parameter = tsmb.getParameter(0);
+ Label success = tsmb.createLabel();
+ Label failure = tsmb.createLabel();
- // Compare fields
- for(int i=0;i<types.length;++i) {
- TypeDesc type = types[i];
- if(type.equals(TypeDesc.VOID))
- continue;
- tsmb.loadThis();
- tsmb.loadField(classBuilder.getClassName(), fieldNamePrefix+i, type);
- tsmb.loadLocal(other);
- tsmb.loadField(classBuilder.getClassName(), fieldNamePrefix+i, type);
- if(type.isPrimitive())
- tsmb.ifComparisonBranch(failure, "!=", type);
- else {
- Label isNull = tsmb.createLabel();
- Label finished = tsmb.createLabel();
- tsmb.swap();
- tsmb.dup();
- tsmb.ifNullBranch(isNull, true);
- tsmb.swap();
- tsmb.invokeVirtual("java/lang/Object", "equals", TypeDesc.BOOLEAN, Constants.OBJECTS[1]);
- tsmb.ifZeroComparisonBranch(failure, "==");
- tsmb.branch(finished);
- tsmb.setLocation(isNull);
- tsmb.pop();
- tsmb.ifNullBranch(failure, false);
- tsmb.setLocation(finished);
- }
- }
+ // Check type
+ tsmb.loadThis();
+ tsmb.loadLocal(parameter);
+ tsmb.ifComparisonBranch(success, "==", TypeDesc.OBJECT);
+ tsmb.loadLocal(parameter);
+ tsmb.ifNullBranch(failure, true);
+ tsmb.loadLocal(parameter);
+ tsmb.invokeVirtual("java/lang/Object", "getClass", CLASS, Constants.EMPTY_TYPEDESC_ARRAY);
+ tsmb.loadThis();
+ tsmb.invokeVirtual("java/lang/Object", "getClass", CLASS, Constants.EMPTY_TYPEDESC_ARRAY);
+ tsmb.ifComparisonBranch(failure, "!=", CLASS);
+ tsmb.loadLocal(parameter);
+ tsmb.checkCast(classBuilder.getType());
+ LocalVariable other = tsmb.createLocalVariable("other", classBuilder.getType());
+ tsmb.storeLocal(other);
- // Return
- tsmb.setLocation(success);
- tsmb.loadConstant(true);
- tsmb.returnValue(TypeDesc.BOOLEAN);
- tsmb.setLocation(failure);
- tsmb.loadConstant(false);
- tsmb.returnValue(TypeDesc.BOOLEAN);
- tsmb.finish();
+ // Compare fields
+ for(int i=0;i<types.length;++i) {
+ TypeDesc type = types[i];
+ if(type.equals(TypeDesc.VOID))
+ continue;
+ tsmb.loadThis();
+ tsmb.loadField(classBuilder.getClassName(), fieldNamePrefix+i, type);
+ tsmb.loadLocal(other);
+ tsmb.loadField(classBuilder.getClassName(), fieldNamePrefix+i, type);
+ equals(tsmb, type, failure);
}
- // Create hashCode
- {
- MethodBuilderBase tsmb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "hashCode", TypeDesc.INT, Constants.EMPTY_TYPEDESC_ARRAY);
- tsmb.loadConstant(recordName.hashCode());
- for(int i=0;i<types.length;++i) {
- TypeDesc type = types[i];
- if(type.equals(TypeDesc.VOID))
- continue;
- tsmb.loadConstant(31);
- tsmb.math(Opcodes.IMUL);
- tsmb.loadThis();
- tsmb.loadField(classBuilder.getClassName(), fieldNamePrefix+i, type);
- switch(type.getTypeCode()) {
- case TypeDesc.INT_CODE:
- break;
- case TypeDesc.OBJECT_CODE: {
- Label isNull = tsmb.createLabel();
- Label finished = tsmb.createLabel();
- tsmb.dup();
- tsmb.ifNullBranch(isNull, true);
- tsmb.invokeVirtual("java/lang/Object", "hashCode", TypeDesc.INT, Constants.EMPTY_TYPEDESC_ARRAY);
- tsmb.branch(finished);
- tsmb.setLocation(isNull);
- tsmb.pop();
- tsmb.loadConstant(0);
- tsmb.setLocation(finished);
- } break;
- case TypeDesc.DOUBLE_CODE:
- tsmb.invokeStatic("java/lang/Double", "doubleToLongBits", TypeDesc.LONG, new TypeDesc[] { TypeDesc.DOUBLE });
- case TypeDesc.LONG_CODE:
- tsmb.dup2();
- tsmb.loadConstant(32);
- tsmb.math(Opcodes.LSHR);
- tsmb.math(Opcodes.LXOR);
- tsmb.convert(TypeDesc.LONG, TypeDesc.INT);
- break;
- case TypeDesc.FLOAT_CODE:
- tsmb.invokeStatic("java/lang/Float", "floatToIntBits", TypeDesc.INT, new TypeDesc[] { TypeDesc.FLOAT });
- break;
- default:
- tsmb.convert(type, TypeDesc.INT);
- }
- tsmb.math(Opcodes.IADD);
- }
- tsmb.returnValue(TypeDesc.INT);
- tsmb.finish();
+ // Return
+ tsmb.setLocation(success);
+ tsmb.loadConstant(true);
+ tsmb.returnValue(TypeDesc.BOOLEAN);
+ tsmb.setLocation(failure);
+ tsmb.loadConstant(false);
+ tsmb.returnValue(TypeDesc.BOOLEAN);
+ tsmb.finish();
+ }
+
+ // Create hashCode
+ {
+ MethodBuilderBase tsmb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "hashCode", TypeDesc.INT, Constants.EMPTY_TYPEDESC_ARRAY);
+ tsmb.loadConstant(recordName.hashCode());
+ for(int i=0;i<types.length;++i) {
+ TypeDesc type = types[i];
+ if(type.equals(TypeDesc.VOID))
+ continue;
+ tsmb.loadConstant(31);
+ tsmb.math(Opcodes.IMUL);
+ tsmb.loadThis();
+ tsmb.loadField(classBuilder.getClassName(), fieldNamePrefix+i, type);
+ hashCode(tsmb, type);
+ tsmb.math(Opcodes.IADD);
}
+ tsmb.returnValue(TypeDesc.INT);
+ tsmb.finish();
+ }
+ }
+
+ public static void equals(MethodBuilderBase mb, TypeDesc typeDesc, Label failure) {
+ if(typeDesc.isPrimitive())
+ mb.ifComparisonBranch(failure, "!=", typeDesc);
+ else {
+ Label isNull = mb.createLabel();
+ Label finished = mb.createLabel();
+ mb.swap();
+ mb.dup();
+ mb.ifNullBranch(isNull, true);
+ mb.swap();
+ mb.invokeVirtual("java/lang/Object", "equals", TypeDesc.BOOLEAN, Constants.OBJECTS[1]);
+ mb.ifZeroComparisonBranch(failure, "==");
+ mb.branch(finished);
+ mb.setLocation(isNull);
+ mb.pop();
+ mb.ifNullBranch(failure, false);
+ mb.setLocation(finished);
+ }
+ }
+
+ /**
+ * Calculates the hash code of a value in stack.
+ */
+ public static void hashCode(MethodBuilderBase mb, TypeDesc typeDesc) {
+ switch(typeDesc.getTypeCode()) {
+ case TypeDesc.INT_CODE:
+ break;
+ case TypeDesc.OBJECT_CODE: {
+ Label isNull = mb.createLabel();
+ Label finished = mb.createLabel();
+ mb.dup();
+ mb.ifNullBranch(isNull, true);
+ mb.invokeVirtual("java/lang/Object", "hashCode", TypeDesc.INT, Constants.EMPTY_TYPEDESC_ARRAY);
+ mb.branch(finished);
+ mb.setLocation(isNull);
+ mb.pop();
+ mb.loadConstant(0);
+ mb.setLocation(finished);
+ } break;
+ case TypeDesc.DOUBLE_CODE:
+ mb.invokeStatic("java/lang/Double", "doubleToLongBits", TypeDesc.LONG, new TypeDesc[] { TypeDesc.DOUBLE });
+ case TypeDesc.LONG_CODE:
+ mb.dup2();
+ mb.loadConstant(32);
+ mb.math(Opcodes.LSHR);
+ mb.math(Opcodes.LXOR);
+ mb.convert(TypeDesc.LONG, TypeDesc.INT);
+ break;
+ case TypeDesc.FLOAT_CODE:
+ mb.invokeStatic("java/lang/Float", "floatToIntBits", TypeDesc.INT, new TypeDesc[] { TypeDesc.FLOAT });
+ break;
+ default:
+ mb.convert(typeDesc, TypeDesc.INT);
}
}