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;
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();
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();
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() {
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;
}
}
}
- 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;
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";
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();
// 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) {
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()));
}
// }
// }
- 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";
}
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;
- }
}