]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRFactCodeGenerator.java
(refs #7250) Merging master, minor CHR bugfixes
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / chr / CHRFactCodeGenerator.java
index 06725ec2b813dc4f0693a3b7a066d2f310a1dd4c..865ab22e6c8e18ed31248bfef8bb17e700a083ac 100644 (file)
@@ -6,42 +6,27 @@ import org.cojen.classfile.TypeDesc;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.Opcodes;
 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
-import org.simantics.scl.compiler.elaboration.chr.plan.PrioritizedPlan;
 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint.IndexInfo;
-import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
-import org.simantics.scl.compiler.internal.codegen.utils.CodeBuilderUtils;
 import org.simantics.scl.compiler.internal.codegen.utils.Constants;
 import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable;
-import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
 
-import gnu.trove.list.array.TIntArrayList;
-import gnu.trove.set.hash.THashSet;
-
-public class CHRFactCodeGenerator {
-    private static final TypeDesc FACT_ID_TYPE = TypeDesc.INT;
-    private static final String CHRHashIndex_name = "org/simantics/scl/runtime/chr/CHRHashIndex";
-    private static final TypeDesc CHRHashIndex = TypeDesc.forClass(CHRHashIndex_name);
-    private static final String FactActivationQueue_name = "org/simantics/scl/runtime/chr/FactActivationQueue";
-    private static final TypeDesc FactActivationQueue = TypeDesc.forClass(FactActivationQueue_name);
-    private static final String Fact_name = "org/simantics/scl/runtime/chr/Fact";
-    private static final TypeDesc Fact = TypeDesc.forClass(Fact_name);
-    private static final String QUEUE = "queue";
+public class CHRFactCodeGenerator implements CHRCodeGenerationConstants {
 
     private ModuleBuilder moduleBuilder; 
     private JavaTypeTranslator jtt;
-    private CHRRuleset ruleset;
 
     private ClassBuilder storeClassBuilder;
+    private CHRRuleset ruleset;
     private CHRConstraint constraint;
 
     private String factClassName;
     private TypeDesc factTypeDesc;
-    private ClassBuilder factClassBuilder;
+    private ClassBuilder classBuilder;
 
     private TypeDesc storeTypeDesc;
     private TypeDesc[] storeTypeDescArray;
@@ -49,10 +34,10 @@ public class CHRFactCodeGenerator {
     private TypeDesc[] parameterTypeDescs;
     private boolean supportsRemoval;
 
-    CHRFactCodeGenerator(ClassBuilder storeClassBuilder, CHRConstraint constraint) {
+    CHRFactCodeGenerator(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRConstraint constraint) {
         this.storeClassBuilder = storeClassBuilder;
+        this.ruleset = ruleset;
         this.constraint = constraint;
-        this.ruleset = constraint.parentRuleset;
 
         this.moduleBuilder = storeClassBuilder.getModuleBuilder();
         this.jtt = moduleBuilder.getJavaTypeTranslator();
@@ -61,7 +46,7 @@ public class CHRFactCodeGenerator {
 
         this.factClassName = storeClassBuilder.getClassName() + "$" + constraint.name;
         this.factTypeDesc = TypeDesc.forClass(factClassName);
-        this.factClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, factClassName, "java/lang/Object", Fact_name);
+        this.classBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, factClassName, CHRFact_name);
 
         this.parameterTypeDescs = jtt.toTypeDescs(constraint.parameterTypes);
         this.supportsRemoval = constraint.mayBeRemoved();
@@ -77,16 +62,10 @@ public class CHRFactCodeGenerator {
         if(supportsRemoval)
             generateRemove();
 
-        generateIsAlive();
-
-        for(int i=0;i<constraint.plans.size();++i) 
-            generateActivateI(i);
-        generateActivate();
-
         generateConstructor();
-        factClassBuilder.addDefaultConstructor();
+        classBuilder.addDefaultConstructor();
 
-        moduleBuilder.addClass(factClassBuilder);
+        moduleBuilder.addClass(classBuilder);
     }
 
     private void generateIndices() {
@@ -116,7 +95,7 @@ public class CHRFactCodeGenerator {
                         if(!typeDesc.equals(TypeDesc.VOID)) {
                             mb.loadLocal(tempFactVar);
                             mb.loadLocal(mb.getParameter(parameterId));
-                            mb.storeField(factClassName, fieldName(i), typeDesc);
+                            mb.storeField(factClassName, CHRCodeGenerationConstants.fieldName(i), typeDesc);
                         }
                         ++parameterId;
                     }
@@ -133,94 +112,6 @@ public class CHRFactCodeGenerator {
         }   
     }
 
-    private THashSet<BoundVar> usedParameters = new THashSet<BoundVar>();
-
-    private void generateActivateI(int i) {
-        PrioritizedPlan plan = constraint.plans.get(i);
-        MethodBuilder mb = factClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "activate" + i, TypeDesc.BOOLEAN, storeTypeDescArray);
-        LocalVariable storeVar = mb.getParameter(0);
-        LocalVariable factVar = new LocalVariable(0, factTypeDesc);
-        mb.setLocalVariable(ruleset.this_, storeVar);
-        mb.setLocalVariable(plan.implementation.getParameters()[0], factVar);
-
-        // Set closure parameters
-        usedParameters.clear();
-        plan.implementation.forValRefs(valRef -> {
-            if(valRef.getBinding() instanceof BoundVar)
-                usedParameters.add((BoundVar)valRef.getBinding());
-        });
-        for(int j=0;j<ruleset.parameters.length;++j) {
-            BoundVar parameter = ruleset.parameters[j];
-            if(!usedParameters.contains(parameter))
-                continue;
-            mb.loadLocal(storeVar);
-            mb.loadField(storeClassBuilder.getClassName(), "p"+j, ruleset.parameterTypeDescs[j]);
-            mb.store(parameter);
-        }
-
-        // Generate code
-        //System.out.println("=== activate" + i + " ==========================================================");
-        //System.out.println(plan.implementation);
-        plan.implementation.markGenerateOnFly();
-        plan.implementation.generateCodeWithAlreadyPreparedParameters(mb);
-        mb.finish();
-    }
-
-    private void generateActivate() {
-        // @Override
-        // public int activate(Object context, int priority) {
-        //     return -1;
-        // }
-
-        MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "activate", TypeDesc.INT, new TypeDesc[] {TypeDesc.OBJECT, TypeDesc.INT});
-        Label defaultLabel = mb.createLabel();
-
-        if(!constraint.isPassive()) {
-            // Check if the fact is alive
-            mb.loadThis();
-            mb.loadField(factClassName, "id", TypeDesc.INT);
-            mb.ifZeroComparisonBranch(defaultLabel, "<");
-
-            mb.loadLocal(mb.getParameter(0));
-            mb.checkCast(storeTypeDesc);
-            LocalVariable storeVariable = new LocalVariable(1, storeTypeDesc);
-            mb.storeLocal(storeVariable);
-
-            TIntArrayList priorities = new TIntArrayList(constraint.plans.size());
-            ArrayList<Label> labels = new ArrayList<Label>();
-            int lastPriority = -1;
-            for(PrioritizedPlan plan : constraint.plans)
-                if(plan.priority != lastPriority) {
-                    priorities.add(plan.priority);
-                    labels.add(mb.createLabel());
-                    lastPriority = plan.priority;
-                }
-
-            mb.loadLocal(mb.getParameter(1));
-            mb.switch_(priorities.toArray(), labels.toArray(new Label[labels.size()]), defaultLabel);
-            int labelId = -1;
-            for(int i=0;i<constraint.plans.size();++i) {
-                PrioritizedPlan plan = constraint.plans.get(i);
-                if(labelId == -1 || plan.priority != priorities.get(labelId)) {
-                    if(labelId >= 0) {
-                        mb.loadConstant(plan.priority);
-                        mb.returnValue(TypeDesc.INT);
-                    }
-                    ++labelId;
-                    mb.setLocation(labels.get(labelId));
-                }
-                mb.loadThis();
-                mb.loadLocal(storeVariable);
-                mb.invokeVirtual(factClassName, "activate" + i, TypeDesc.BOOLEAN, new TypeDesc[] {storeTypeDesc});
-                mb.ifZeroComparisonBranch(defaultLabel, "==");
-            }
-            mb.setLocation(defaultLabel);
-        }
-        mb.loadConstant(-1);
-        mb.returnValue(TypeDesc.INT);
-        mb.finish();
-    }
-
     private void generateConstructor() {
         // public ExampleFact(int id, int c0, int c1) {
         //     this.id = id;            
@@ -235,54 +126,29 @@ public class CHRFactCodeGenerator {
                 continue;
             constructorParameters.add(typeDesc);
         }
-        MethodBuilderBase mb = factClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, constructorParameters.toArray(new TypeDesc[constructorParameters.size()]));
+        MethodBuilderBase mb = classBuilder.addConstructorBase(Opcodes.ACC_PUBLIC, constructorParameters.toArray(new TypeDesc[constructorParameters.size()]));
         mb.loadThis();
-        mb.invokeConstructor(factClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
+        mb.invokeConstructor(classBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
         mb.loadThis();
         mb.loadLocal(mb.getParameter(0));
-        mb.storeField(factClassName, "id", FACT_ID_TYPE);
+        mb.storeField(CHRFact_name, "id", FACT_ID_TYPE);
         for(int i=0,parameterId=1;i<constraint.parameterTypes.length;++i) {
             TypeDesc typeDesc = parameterTypeDescs[i];
             if(typeDesc.equals(TypeDesc.VOID))
                 continue;
             mb.loadThis();
             mb.loadLocal(mb.getParameter(parameterId++));
-            mb.storeField(factClassName, fieldName(i), typeDesc);
+            mb.storeField(factClassName, CHRCodeGenerationConstants.fieldName(i), typeDesc);
         }
         mb.returnVoid();
         mb.finish();
     }
 
-    private void generateIsAlive() {
-        // @Override
-        // public boolean isAlive() {
-        //     return id >= 0;
-        // }
-
-        MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "isAlive", TypeDesc.BOOLEAN, Constants.EMPTY_TYPEDESC_ARRAY);
-        if(supportsRemoval) {
-            mb.loadThis();
-            mb.loadField(factClassName, "id", FACT_ID_TYPE);
-
-            Label thenBranch = mb.createLabel();
-            mb.ifZeroComparisonBranch(thenBranch, "<");
-            mb.loadConstant(true);
-            mb.returnValue(TypeDesc.BOOLEAN);
-
-            mb.setLocation(thenBranch);
-            mb.loadConstant(false);
-            mb.returnValue(TypeDesc.BOOLEAN);
-        }
-        else {
-            mb.loadConstant(true);
-            mb.returnValue(TypeDesc.BOOLEAN);
-        }
-        mb.finish();
-    }
-
     private void generateAdd() {
-        MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "add", TypeDesc.VOID, storeTypeDescArray);
+        MethodBuilderBase mb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "add", TypeDesc.VOID, new TypeDesc[] {storeTypeDesc, CHRContext});
         LocalVariable storeParameter = mb.getParameter(0);
+        
+        // Add fact to indices
         for(IndexInfo indexInfo : constraint.getIndices()) {
             String linkedListPrev = indexInfo.indexName + "Prev";
             String linkedListNext = indexInfo.indexName + "Next";
@@ -339,13 +205,32 @@ public class CHRFactCodeGenerator {
                     mb.setLocation(cont);
                 }
             }
-        }            
-        if(!constraint.isPassive()) {
+        }
+        
+        // Add fact to priority queue
+        int minimumPriority = ruleset.getMinimumPriority(constraint);
+        if(minimumPriority != Integer.MAX_VALUE) {
             mb.loadLocal(storeParameter);
-            mb.loadField(storeClassBuilder.getClassName(), QUEUE, FactActivationQueue);
-            mb.loadConstant(constraint.getMinimumPriority());
+            mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.priorityName(minimumPriority), CHRPriorityFactContainer);
+            mb.loadLocal(mb.getParameter(1));
+            mb.loadThis();
+            mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
+        }
+        else if(constraint.nextContainerFieldName != null) {
+            mb.loadLocal(storeParameter);
+            mb.loadField(storeClassBuilder.getClassName(), constraint.nextContainerFieldName, CHRPriorityFactContainer);
+            LocalVariable containerVar = mb.createLocalVariable("container", CHRPriorityFactContainer);
+            mb.storeLocal(containerVar);
+            
+            mb.loadLocal(containerVar);
+            Label finishLabel = mb.createLabel();
+            mb.ifNullBranch(finishLabel, true);
+            
+            mb.loadLocal(containerVar);
+            mb.loadLocal(mb.getParameter(1));
             mb.loadThis();
-            mb.invokeVirtual(FactActivationQueue_name, "add", TypeDesc.VOID, new TypeDesc[] {TypeDesc.INT, Fact});
+            mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
+            mb.setLocation(finishLabel);
         }
         mb.returnVoid();
         mb.finish();
@@ -358,19 +243,19 @@ public class CHRFactCodeGenerator {
         // public ExampleFact bfPrev;
         // public ExampleFact bfNext;
 
-        factClassBuilder.addField(Opcodes.ACC_PUBLIC, "id", FACT_ID_TYPE);
+        //classBuilder.addField(Opcodes.ACC_PUBLIC, "id", FACT_ID_TYPE);
         for(int i=0;i<constraint.parameterTypes.length;++i) {
             TypeDesc typeDesc = parameterTypeDescs[i];
             if(typeDesc.equals(TypeDesc.VOID))
                 continue;
             if(parameterTypeDescs[i] != TypeDesc.VOID)
-                factClassBuilder.addField(Opcodes.ACC_PUBLIC, fieldName(i), typeDesc);
+                classBuilder.addField(Opcodes.ACC_PUBLIC, CHRCodeGenerationConstants.fieldName(i), typeDesc);
         }
 
         for(IndexInfo indexInfo : constraint.getIndices()) {
             if(supportsRemoval)
-                factClassBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Prev", factTypeDesc);
-            factClassBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Next", factTypeDesc);
+                classBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Prev", factTypeDesc);
+            classBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Next", factTypeDesc);
 
             String hashIndexField = constraint.name + "$" + indexInfo.indexName;
             if(indexInfo.indexMask == 0) {
@@ -378,7 +263,7 @@ public class CHRFactCodeGenerator {
                 storeClassBuilder.addField(Opcodes.ACC_PUBLIC, hashIndexField, factTypeDesc);
             }
             else {
-                ClassBuilder hashClass = generateSpecializedHashIndex(storeClassBuilder, constraint, indexInfo, factTypeDesc, factClassName);
+                ClassBuilder hashClass = CHRHashIndexCodeGenerator.generateHashIndex(storeClassBuilder, constraint, indexInfo, factTypeDesc, factClassName);
                 moduleBuilder.addClass(hashClass);
                 hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, hashIndexField, CHRHashIndex, hashClass.getClassName()));
             }
@@ -402,7 +287,7 @@ public class CHRFactCodeGenerator {
         //     }
         // }
 
-        MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "remove", TypeDesc.VOID, storeTypeDescArray);
+        MethodBuilderBase mb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "remove", TypeDesc.VOID, storeTypeDescArray);
         LocalVariable storeParameter = mb.getParameter(0);
         for(IndexInfo indexInfo : constraint.getIndices()) {
             String linkedListPrev = indexInfo.indexName + "Prev";
@@ -489,114 +374,8 @@ public class CHRFactCodeGenerator {
         }
         mb.loadThis();
         mb.loadConstant(-1);
-        mb.storeField(factClassName, "id", FACT_ID_TYPE);
+        mb.storeField(CHRFact_name, "id", FACT_ID_TYPE);
         mb.returnVoid();
         mb.finish();
     }
-
-    public static String fieldName(int id) {
-        return "c" + id;
-    }
-
-    private static ClassBuilder generateSpecializedHashIndex(ClassBuilder storeClassBuilder, CHRConstraint constraint, IndexInfo indexInfo, TypeDesc factClassTypeDesc, String factClassName) {
-        // new CHRHashIndex() {
-        //     @Override
-        //     protected boolean keyEquals(Object a, Object b) {
-        //         return ((ExampleFact)a).c0 == ((ExampleFact)b).c0;
-        //     }
-        //     @Override
-        //     protected int keyHashCode(Object key) {
-        //         return ((ExampleFact)key).c0;
-        //     }
-        // }
-
-        ModuleBuilder moduleBuilder = storeClassBuilder.getModuleBuilder();
-        JavaTypeTranslator jtt = moduleBuilder.getJavaTypeTranslator();
-
-        String hashIndexClassName = factClassName + "$" + indexInfo.indexName; 
-        ClassBuilder hashIndexClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, hashIndexClassName, "org/simantics/scl/runtime/chr/CHRHashIndex");
-
-        // Method: keyEquals
-
-        {
-
-            // @Override
-            // protected boolean keyEquals(Object a, Object b) {
-            //     return ((ExampleFact)a).c0 == ((ExampleFact)b).c0;
-            // }
-
-            MethodBuilderBase mb = hashIndexClassBuilder.addMethodBase(Opcodes.ACC_PROTECTED, "keyEquals", TypeDesc.BOOLEAN, Constants.OBJECTS[2]);
-            mb.loadLocal(mb.getParameter(0));
-            mb.checkCast(factClassTypeDesc);
-            LocalVariable aVar = mb.createLocalVariable("a", factClassTypeDesc);
-            mb.storeLocal(aVar);
-
-            mb.loadLocal(mb.getParameter(1));
-            mb.checkCast(factClassTypeDesc);
-            LocalVariable bVar = mb.createLocalVariable("b", factClassTypeDesc);
-            mb.storeLocal(bVar);
-
-            Label failure = mb.createLabel();
-
-            int curMask = indexInfo.indexMask;
-            for(int i=0;i<constraint.parameterTypes.length;++i,curMask>>=1)
-                if((curMask&1) == 1) {
-                    TypeDesc fieldTypeDesc = jtt.toTypeDesc(constraint.parameterTypes[i]);
-                    if(fieldTypeDesc.equals(TypeDesc.VOID))
-                        continue;
-                    mb.loadLocal(aVar);
-                    mb.loadField(factClassName, fieldName(i), fieldTypeDesc);
-
-                    mb.loadLocal(bVar);
-                    mb.loadField(factClassName, fieldName(i), fieldTypeDesc);
-
-                    CodeBuilderUtils.equals(mb, fieldTypeDesc, failure);
-                }
-            mb.loadConstant(true);
-            mb.returnValue(TypeDesc.BOOLEAN);
-
-            mb.setLocation(failure);
-            mb.loadConstant(false);
-            mb.returnValue(TypeDesc.BOOLEAN);
-            mb.finish();
-        }
-
-        // Method: keyHashCode
-
-        {
-            // @Override
-            // protected int keyHashCode(Object key) {
-            //     return (0x811C9DC5^((ExampleFact)key).c0)*16777619;
-            // }
-
-            MethodBuilderBase mb = hashIndexClassBuilder.addMethodBase(Opcodes.ACC_PROTECTED, "keyHashCode", TypeDesc.INT, Constants.OBJECTS[1]);
-            mb.loadLocal(mb.getParameter(0));
-            mb.checkCast(factClassTypeDesc);
-            LocalVariable factVar = mb.createLocalVariable("fact", factClassTypeDesc);
-            mb.storeLocal(factVar);
-
-            mb.loadConstant(0x811C9DC5);
-
-            int curMask = indexInfo.indexMask;
-            for(int i=0;i<constraint.parameterTypes.length;++i,curMask>>=1)
-                if((curMask&1) == 1) {
-                    TypeDesc fieldTypeDesc = jtt.toTypeDesc(constraint.parameterTypes[i]);
-                    if(fieldTypeDesc.equals(TypeDesc.VOID))
-                        continue;
-                    mb.loadLocal(factVar);
-                    mb.loadField(factClassName, fieldName(i), fieldTypeDesc);
-                    CodeBuilderUtils.hashCode(mb, fieldTypeDesc);
-                    mb.math(Opcodes.IXOR);
-                    mb.loadConstant(16777619);
-                    mb.math(Opcodes.IMUL);
-
-                }
-            mb.returnValue(TypeDesc.INT);
-            mb.finish();
-        }
-
-        hashIndexClassBuilder.addDefaultConstructor();
-
-        return hashIndexClassBuilder;
-    }
 }