X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Finternal%2Fcodegen%2Fchr%2FCHRCodeGenerator.java;fp=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Finternal%2Fcodegen%2Fchr%2FCHRCodeGenerator.java;h=bd7059ee209a15f90c8985b1e89a70e52d82d22e;hb=a8758de5bc19e5adb3f618d3038743a164f09912;hp=0000000000000000000000000000000000000000;hpb=12d9af17384d960b75d58c3935d2b7b46d93e87b;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRCodeGenerator.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRCodeGenerator.java new file mode 100644 index 000000000..bd7059ee2 --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRCodeGenerator.java @@ -0,0 +1,648 @@ +package org.simantics.scl.compiler.internal.codegen.chr; + +import java.util.ArrayList; + +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 CHRCodeGenerator { + + public static final TypeDesc FACT_ID_TYPE = TypeDesc.INT; + public static final String CHRHashIndex_name = "org/simantics/scl/runtime/chr/CHRHashIndex"; + public static final TypeDesc CHRHashIndex = TypeDesc.forClass(CHRHashIndex_name); + public static final String FactActivationQueue_name = "org/simantics/scl/runtime/chr/FactActivationQueue"; + public static final TypeDesc FactActivationQueue = TypeDesc.forClass(FactActivationQueue_name); + public static final String Fact_name = "org/simantics/scl/runtime/chr/Fact"; + public static final TypeDesc Fact = TypeDesc.forClass(Fact_name); + public static final String QUEUE = "queue"; + + private static class StoreInitialization { + final int access; + final String fieldName; + final TypeDesc fieldType; + final String className; + public StoreInitialization(int access, String fieldName, TypeDesc fieldType, String className) { + this.access = access; + this.fieldName = fieldName; + this.fieldType = fieldType; + this.className = className; + } + } + + public static void generateStore(ModuleBuilder moduleBuilder, CHRRuleset ruleset) { + ClassBuilder storeClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, ruleset.storeClassName, "java/lang/Object"); + if(ruleset.parameters == null) + ruleset.parameters = new BoundVar[0]; + ruleset.parameterTypeDescs = moduleBuilder.getJavaTypeTranslator().getTypeDescs(ruleset.parameters); + + ArrayList hashIndexInitializations = new ArrayList<>(); + for(CHRConstraint constraint : ruleset.constraints) + generateFact(storeClassBuilder, constraint, hashIndexInitializations); + + // Fields + for(int i=0;i hashIndexInitializations) { + CHRRuleset ruleset = constraint.parentRuleset; + boolean supportsRemoval = constraint.mayBeRemoved(); + + ModuleBuilder moduleBuilder = storeClassBuilder.getModuleBuilder(); + JavaTypeTranslator jtt = moduleBuilder.getJavaTypeTranslator(); + TypeDesc storeTypeDesc = storeClassBuilder.getType(); + TypeDesc[] storeTypeDescArray = new TypeDesc[] { storeTypeDesc }; + + String factClassName = storeClassBuilder.getClassName() + "$" + constraint.name; + TypeDesc factTypeDesc = TypeDesc.forClass(factClassName); + ClassBuilder factClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, factClassName, "java/lang/Object", Fact_name); + + // Fields + + /* public int id; + public int c0; // key + public int c1; + public ExampleFact bfPrev; + public ExampleFact bfNext; + */ + TypeDesc[] parameterTypeDescs = jtt.toTypeDescs(constraint.parameterTypes); + factClassBuilder.addField(Opcodes.ACC_PUBLIC, "id", FACT_ID_TYPE); + for(int i=0;i getParameterTypeDescs = new ArrayList(constraint.parameterTypes.length); + for(int i=0;i>i)&1)==1) + getParameterTypeDescs.add(parameterTypeDescs[i]); + MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, constraint.name + "$" + indexInfo.indexName, factTypeDesc, + getParameterTypeDescs.toArray(new TypeDesc[getParameterTypeDescs.size()])); + mb.loadThis(); + mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$temp", factTypeDesc); + LocalVariable tempFactVar = mb.createLocalVariable("temp", factTypeDesc); + mb.storeLocal(tempFactVar); + int parameterId=0; + for(int i=0;i>i)&1)==1) { + mb.loadLocal(tempFactVar); + mb.loadLocal(mb.getParameter(parameterId++)); + mb.storeField(factClassName, "c"+i, parameterTypeDescs[i]); + } + + mb.loadThis(); + mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$" + indexInfo.indexName, CHRHashIndex); + mb.loadLocal(tempFactVar); + mb.invokeVirtual(CHRHashIndex_name, supportsRemoval ? "getEqual" : "getEqualNoRemovals", TypeDesc.OBJECT, Constants.OBJECTS[1]); + mb.checkCast(factTypeDesc); + + mb.returnValue(factTypeDesc); + mb.finish(); + } + } + } + + // Method: add + + { + MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "add", TypeDesc.VOID, storeTypeDescArray); + LocalVariable storeParameter = mb.getParameter(0); + for(IndexInfo indexInfo : constraint.getIndices()) { + String linkedListPrev = indexInfo.indexName + "Prev"; + String linkedListNext = indexInfo.indexName + "Next"; + String storeHashIndexName = constraint.name + "$" + indexInfo.indexName; + + // public void add(ExampleStore store) { + // bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this); + // if(bfNext != null) + // bfNext.bfPrev = this; + // } + + if(indexInfo.indexMask == 0) { + mb.loadThis(); + mb.loadLocal(storeParameter); + mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc); + if(supportsRemoval) + mb.dupX1(); + mb.storeField(factClassName, linkedListNext, factTypeDesc); + if(supportsRemoval) { + Label cont = new Label(); + mb.ifNullBranch(cont, true); + mb.loadThis(); + mb.loadField(factClassName, linkedListNext, factTypeDesc); + mb.loadThis(); + mb.storeField(factClassName, linkedListPrev, factTypeDesc); + mb.setLocation(cont); + } + mb.loadLocal(storeParameter); + mb.loadThis(); + mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc); + } + else { + // bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this); + mb.loadThis(); + mb.loadLocal(storeParameter); + mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex); + mb.loadThis(); + mb.invokeVirtual(CHRHashIndex_name, supportsRemoval ? "addFreshAndReturnOld" : "addFreshAndReturnOld", TypeDesc.OBJECT, Constants.OBJECTS[1]); + mb.checkCast(factTypeDesc); + if(supportsRemoval) + mb.dupX1(); + mb.storeField(factClassName, linkedListNext, factTypeDesc); + // leaves bfNext on the stack + + //if(bfNext != null) + // bfNext.bfPrev = this; + if(supportsRemoval) { + Label cont = new Label(); + mb.ifNullBranch(cont, true); + mb.loadThis(); + mb.loadField(factClassName, linkedListNext, factTypeDesc); + mb.loadThis(); + mb.storeField(factClassName, linkedListPrev, factTypeDesc); + mb.setLocation(cont); + } + } + } + if(!constraint.isPassive()) { + mb.loadLocal(storeParameter); + mb.loadField(storeClassBuilder.getClassName(), QUEUE, FactActivationQueue); + mb.loadConstant(constraint.getMinimumPriority()); + mb.loadThis(); + mb.invokeVirtual(FactActivationQueue_name, "add", TypeDesc.VOID, new TypeDesc[] {TypeDesc.INT, Fact}); + } + mb.returnVoid(); + mb.finish(); + } + + // Method: remove + + if(supportsRemoval) { + // public void remove(ExampleStore store) { + // if(bfPrev == null) { + // if(bfNext == null) + // store.ExampleFact_bfIndex.removeKnownToExistKey(this); + // else { + // bfNext.bfPrev = null; + // store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext); + // } + // } + // else { + // bfPrev.bfNext = bfNext; + // if(bfNext != null) + // bfNext.bfPrev = bfPrev; + // } + // } + + MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "remove", TypeDesc.VOID, storeTypeDescArray); + LocalVariable storeParameter = mb.getParameter(0); + for(IndexInfo indexInfo : constraint.getIndices()) { + String linkedListPrev = indexInfo.indexName + "Prev"; + String linkedListNext = indexInfo.indexName + "Next"; + String storeHashIndexName = constraint.name + "$" + indexInfo.indexName; + + Label nextIndex = mb.createLabel(); + + // if(bfPrev == null) { + mb.loadThis(); + mb.loadField(factClassName, linkedListPrev, factTypeDesc); + Label else1 = new Label(); + mb.ifNullBranch(else1, false); + + // if(bfNext == null) + mb.loadThis(); + mb.loadField(factClassName, linkedListNext, factTypeDesc); + Label else2 = new Label(); + mb.ifNullBranch(else2, false); + + // store.ExampleFact_bfIndex.removeKnownToExistKey(this); + if(indexInfo.indexMask == 0) { + mb.loadLocal(storeParameter); + mb.loadNull(); + mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc); + } + else { + mb.loadLocal(storeParameter); + mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex); + mb.loadThis(); + mb.invokeVirtual(CHRHashIndex_name, "removeKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[1]); + } + mb.branch(nextIndex); + + // else { + mb.setLocation(else2); + // bfNext.bfPrev = null; + mb.loadThis(); + mb.loadField(factClassName, linkedListNext, factTypeDesc); + mb.loadNull(); + mb.storeField(factClassName, linkedListPrev, factTypeDesc); + // store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext); + if(indexInfo.indexMask == 0) { + mb.loadLocal(storeParameter); + mb.loadThis(); + mb.loadField(factClassName, linkedListNext, factTypeDesc); + mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc); + } + else { + mb.loadLocal(storeParameter); + mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex); + mb.loadThis(); + mb.loadThis(); + mb.loadField(factClassName, linkedListNext, factTypeDesc); + mb.invokeVirtual(CHRHashIndex_name, "replaceKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[2]); + } + mb.branch(nextIndex); + // } + + // else { + mb.setLocation(else1); + // bfPrev.bfNext = bfNext; + mb.loadThis(); + mb.loadField(factClassName, linkedListPrev, factTypeDesc); + mb.loadThis(); + mb.loadField(factClassName, linkedListNext, factTypeDesc); + mb.storeField(factClassName, linkedListNext, factTypeDesc); + // if(bfNext != null) + mb.loadThis(); + mb.loadField(factClassName, linkedListNext, factTypeDesc); + Label else3 = new Label(); + mb.ifNullBranch(else3, true); + // bfNext.bfPrev = bfPrev; + mb.loadThis(); + mb.loadField(factClassName, linkedListNext, factTypeDesc); + mb.loadThis(); + mb.loadField(factClassName, linkedListPrev, factTypeDesc); + mb.storeField(factClassName, linkedListPrev, factTypeDesc); + mb.setLocation(else3); + mb.branch(nextIndex); + // } + + mb.setLocation(nextIndex); + } + mb.loadThis(); + mb.loadConstant(-1); + mb.storeField(factClassName, "id", FACT_ID_TYPE); + mb.returnVoid(); + mb.finish(); + } + + // Method: isAlive + + { + // @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(); + } + + // activate parts + + THashSet usedParameters = new THashSet(); + for(int i=0;i { + if(valRef.getBinding() instanceof BoundVar) + usedParameters.add((BoundVar)valRef.getBinding()); + }); + for(int j=0;j labels = new ArrayList