import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
import org.simantics.scl.compiler.elaboration.chr.plan.PrioritizedPlan;
import org.simantics.scl.compiler.internal.codegen.chr.CHRCodeGenerator;
+import org.simantics.scl.compiler.internal.codegen.chr.CHRFactCodeGenerator;
import org.simantics.scl.compiler.internal.codegen.references.IVal;
import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
import org.simantics.scl.compiler.internal.codegen.types.StandardTypeConstructor;
if(typeDesc.equals(TypeDesc.VOID))
continue;
this.accessors[i] = new CallJava(TVar.EMPTY_ARRAY, Types.NO_EFFECTS, parameterTypes[i], new Type[] {factType},
- null, new FieldRef(factClassName, CHRCodeGenerator.fieldName(i), jtt.toTypeDesc(parameterTypes[i])), null);
+ null, new FieldRef(factClassName, CHRFactCodeGenerator.fieldName(i), jtt.toTypeDesc(parameterTypes[i])), null);
}
this.addProcedure = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {parentRuleset.storeType, factType},
new StackItem[] {new ParameterStackItem(1, factType), new ParameterStackItem(0, parentRuleset.storeType)},
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;
- }
- }
-
+ 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 QUEUE = "queue";
+
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<StoreInitialization> hashIndexInitializations = new ArrayList<>();
for(CHRConstraint constraint : ruleset.constraints)
generateFact(storeClassBuilder, constraint, hashIndexInitializations);
-
+
// Fields
for(int i=0;i<ruleset.parameterTypeDescs.length;++i) {
TypeDesc typeDesc = ruleset.parameterTypeDescs[i];
for(StoreInitialization ini : hashIndexInitializations)
storeClassBuilder.addField(ini.access, ini.fieldName, ini.fieldType);
storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, QUEUE, FactActivationQueue);
-
+
// Constructors
-
+
{
MethodBuilderBase mb = storeClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, ruleset.parameterTypeDescs);
mb.loadThis();
mb.returnVoid();
mb.finish();
}
-
+
// Activate
-
+
{
MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "activate", TypeDesc.VOID, new TypeDesc[] {TypeDesc.INT});
mb.loadThis();
mb.returnVoid();
mb.finish();
}
-
- moduleBuilder.addClass(storeClassBuilder);
- }
-
- private static void generateFact(ClassBuilder storeClassBuilder, CHRConstraint constraint, ArrayList<StoreInitialization> 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<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);
- }
-
- 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);
-
- String hashIndexField = constraint.name + "$" + indexInfo.indexName;
- if(indexInfo.indexMask == 0) {
- // If there are now bound parameters, use just a direct reference to a fact
- storeClassBuilder.addField(Opcodes.ACC_PUBLIC, hashIndexField, factTypeDesc);
- }
- else {
- ClassBuilder hashClass = generateSpecializedHashIndex(storeClassBuilder, constraint, indexInfo, factTypeDesc, factClassName);
- moduleBuilder.addClass(hashClass);
- hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, hashIndexField, CHRHashIndex, hashClass.getClassName()));
- }
- }
-
- // Method: get
-
- hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, constraint.name + "$temp", factTypeDesc, factClassName));
-
-
- {
- /*
- public ExampleFact ExampleFact$bf(int c0) {
- ExampleFact$temp.c0 = c0;
- return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp);
- }
- */
- for(IndexInfo indexInfo : constraint.getIndices()) {
- /*if(indexInfo.indexMask == 0) {
- MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, constraint.name + "$" + indexInfo.indexName,
- factTypeDesc, Constants.EMPTY_TYPEDESC_ARRAY);
- mb.loadThis();
- mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$" + indexInfo.indexName, factTypeDesc);
- mb.returnValue(factTypeDesc);
- mb.finish();
- }*/
- if(indexInfo.indexMask != 0) {
- ArrayList<TypeDesc> getParameterTypeDescs = new ArrayList<TypeDesc>(constraint.parameterTypes.length);
- for(int i=0;i<constraint.parameterTypes.length;++i)
- if(((indexInfo.indexMask>>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<constraint.parameterTypes.length;++i)
- if(((indexInfo.indexMask>>i)&1)==1) {
- TypeDesc typeDesc = parameterTypeDescs[i];
- if(!typeDesc.equals(TypeDesc.VOID)) {
- mb.loadLocal(tempFactVar);
- mb.loadLocal(mb.getParameter(parameterId));
- mb.storeField(factClassName, fieldName(i), typeDesc);
- }
- ++parameterId;
- }
-
- 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<BoundVar> usedParameters = new THashSet<BoundVar>();
- for(int i=0;i<constraint.plans.size();++i) {
- PrioritizedPlan plan = constraint.plans.get(i);
- MethodBuilder mb = factClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "activate" + i, TypeDesc.BOOLEAN, new TypeDesc[] {storeTypeDesc});
- 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();
- }
-
- // Method: activate
-
- {
- // @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();
- }
-
- // Constructors
-
- {
- // public ExampleFact(int id, int c0, int c1) {
- // this.id = id;
- // this.c0 = c0;
- // this.c1 = c1;
- // }
-
- ArrayList<TypeDesc> constructorParameters = new ArrayList<TypeDesc>(parameterTypeDescs.length+1);
- constructorParameters.add(FACT_ID_TYPE);
- for(TypeDesc typeDesc : parameterTypeDescs) {
- if(typeDesc.equals(TypeDesc.VOID))
- continue;
- constructorParameters.add(typeDesc);
- }
- MethodBuilderBase mb = factClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, constructorParameters.toArray(new TypeDesc[constructorParameters.size()]));
- mb.loadThis();
- mb.invokeConstructor(factClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
- mb.loadThis();
- mb.loadLocal(mb.getParameter(0));
- mb.storeField(factClassName, "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.returnVoid();
- mb.finish();
- }
- factClassBuilder.addDefaultConstructor();
-
- moduleBuilder.addClass(factClassBuilder);
+ moduleBuilder.addClass(storeClassBuilder);
}
- 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;
- }
-
- public static String fieldName(int id) {
- return "c" + id;
+ private static void generateFact(ClassBuilder storeClassBuilder, CHRConstraint constraint, ArrayList<StoreInitialization> hashIndexInitializations) {
+ CHRFactCodeGenerator generator = new CHRFactCodeGenerator(storeClassBuilder, constraint);
+ generator.generate(hashIndexInitializations);
}
}
--- /dev/null
+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 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";
+
+ private ModuleBuilder moduleBuilder;
+ private JavaTypeTranslator jtt;
+ private CHRRuleset ruleset;
+
+ private ClassBuilder storeClassBuilder;
+ private CHRConstraint constraint;
+
+ private String factClassName;
+ private TypeDesc factTypeDesc;
+ private ClassBuilder factClassBuilder;
+
+ private TypeDesc storeTypeDesc;
+ private TypeDesc[] storeTypeDescArray;
+
+ private TypeDesc[] parameterTypeDescs;
+ private boolean supportsRemoval;
+
+ CHRFactCodeGenerator(ClassBuilder storeClassBuilder, CHRConstraint constraint) {
+ this.storeClassBuilder = storeClassBuilder;
+ this.constraint = constraint;
+ this.ruleset = constraint.parentRuleset;
+
+ this.moduleBuilder = storeClassBuilder.getModuleBuilder();
+ this.jtt = moduleBuilder.getJavaTypeTranslator();
+ this.storeTypeDesc = storeClassBuilder.getType();
+ this.storeTypeDescArray = new TypeDesc[] { storeTypeDesc };
+
+ 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.parameterTypeDescs = jtt.toTypeDescs(constraint.parameterTypes);
+ this.supportsRemoval = constraint.mayBeRemoved();
+ }
+
+ public void generate(ArrayList<StoreInitialization> hashIndexInitializations) {
+ generateFields(hashIndexInitializations);
+ hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, constraint.name + "$temp", factTypeDesc, factClassName));
+
+ generateIndices();
+ generateAdd();
+
+ if(supportsRemoval)
+ generateRemove();
+
+ generateIsAlive();
+
+ for(int i=0;i<constraint.plans.size();++i)
+ generateActivateI(i);
+ generateActivate();
+
+ generateConstructor();
+ factClassBuilder.addDefaultConstructor();
+
+ moduleBuilder.addClass(factClassBuilder);
+ }
+
+ private void generateIndices() {
+ // public ExampleFact ExampleFact$bf(int c0) {
+ // ExampleFact$temp.c0 = c0;
+ // return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp);
+ // }
+
+ for(IndexInfo indexInfo : constraint.getIndices()) {
+ if(indexInfo.indexMask != 0) {
+ ArrayList<TypeDesc> getParameterTypeDescs = new ArrayList<TypeDesc>(constraint.parameterTypes.length);
+ for(int i=0;i<constraint.parameterTypes.length;++i)
+ if(((indexInfo.indexMask>>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()]));
+
+ // ExampleFact$temp.c0 = c0;
+ 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<constraint.parameterTypes.length;++i)
+ if(((indexInfo.indexMask>>i)&1)==1) {
+ TypeDesc typeDesc = parameterTypeDescs[i];
+ if(!typeDesc.equals(TypeDesc.VOID)) {
+ mb.loadLocal(tempFactVar);
+ mb.loadLocal(mb.getParameter(parameterId));
+ mb.storeField(factClassName, fieldName(i), typeDesc);
+ }
+ ++parameterId;
+ }
+
+ // return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp);
+ 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();
+ }
+ }
+ }
+
+ 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;
+ // this.c0 = c0;
+ // this.c1 = c1;
+ // }
+
+ ArrayList<TypeDesc> constructorParameters = new ArrayList<TypeDesc>(parameterTypeDescs.length+1);
+ constructorParameters.add(FACT_ID_TYPE);
+ for(TypeDesc typeDesc : parameterTypeDescs) {
+ if(typeDesc.equals(TypeDesc.VOID))
+ continue;
+ constructorParameters.add(typeDesc);
+ }
+ MethodBuilderBase mb = factClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, constructorParameters.toArray(new TypeDesc[constructorParameters.size()]));
+ mb.loadThis();
+ mb.invokeConstructor(factClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
+ mb.loadThis();
+ mb.loadLocal(mb.getParameter(0));
+ mb.storeField(factClassName, "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.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);
+ 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();
+ }
+
+ private void generateFields(ArrayList<StoreInitialization> hashIndexInitializations) {
+ // public int id;
+ // public int c0; // key
+ // public int c1;
+ // public ExampleFact bfPrev;
+ // public ExampleFact bfNext;
+
+ factClassBuilder.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);
+ }
+
+ 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);
+
+ String hashIndexField = constraint.name + "$" + indexInfo.indexName;
+ if(indexInfo.indexMask == 0) {
+ // If there are no bound parameters, use just a direct reference to a fact
+ storeClassBuilder.addField(Opcodes.ACC_PUBLIC, hashIndexField, factTypeDesc);
+ }
+ else {
+ ClassBuilder hashClass = generateSpecializedHashIndex(storeClassBuilder, constraint, indexInfo, factTypeDesc, factClassName);
+ moduleBuilder.addClass(hashClass);
+ hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, hashIndexField, CHRHashIndex, hashClass.getClassName()));
+ }
+ }
+ }
+
+ private void generateRemove() {
+ // 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();
+ }
+
+ 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;
+ }
+}
--- /dev/null
+package org.simantics.scl.compiler.internal.codegen.chr;
+
+import org.cojen.classfile.TypeDesc;
+
+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;
+ }
+}
\ No newline at end of file