]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/CodeBuilderUtils.java
(refs #7250) Merging master, minor CHR bugfixes
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / utils / CodeBuilderUtils.java
index ec44be75a1531adf48204c4d78653c09c87cb340..71ce63e5c360d11eb7d5f76b2dd13d85e1838327 100644 (file)
@@ -27,7 +27,7 @@ public class CodeBuilderUtils {
                 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();
@@ -93,117 +93,131 @@ public class CodeBuilderUtils {
             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);
         }
     }