1 package org.simantics.scl.compiler.internal.codegen.chr;
3 import java.util.ArrayList;
4 import java.util.concurrent.atomic.AtomicReference;
6 import org.cojen.classfile.TypeDesc;
7 import org.objectweb.asm.Label;
8 import org.objectweb.asm.Opcodes;
9 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
10 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
11 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
12 import org.simantics.scl.compiler.elaboration.chr.plan.CHRSearchPlan;
13 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
14 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
15 import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable;
16 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
17 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
19 import gnu.trove.map.hash.THashMap;
20 import gnu.trove.procedure.TObjectObjectProcedure;
22 public class CHRPriorityFactContainerCodeGenerator implements CHRCodeGenerationConstants {
23 ClassBuilder storeClassBuilder;
24 String containerClassName;
25 private TypeDesc containerTypeDesc;
27 private ClassBuilder classBuilder;
29 private TypeDesc storeTypeDesc;
31 private CHRRuleset ruleset;
34 public CHRPriorityFactContainerCodeGenerator(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRRule rule) {
35 this.storeClassBuilder = storeClassBuilder;
37 this.containerClassName = storeClassBuilder.getClassName() + "$" + "CHRPriorityFactContainer" + rule.priority;
38 this.containerTypeDesc = TypeDesc.forClass(containerClassName);
39 this.classBuilder = new ClassBuilder(storeClassBuilder.getModuleBuilder(), Opcodes.ACC_PUBLIC, containerClassName, CHRPriorityFactContainer_name);
41 this.storeTypeDesc = storeClassBuilder.getType();
43 this.ruleset = ruleset;
47 public void generate() {
51 THashMap<CHRConstraint, ArrayList<CHRSearchPlan>> planMap = new THashMap<CHRConstraint, ArrayList<CHRSearchPlan>>();
52 for(CHRSearchPlan plan : rule.plans) {
53 ArrayList<CHRSearchPlan> list = planMap.get(plan.constraint);
55 list = new ArrayList<CHRSearchPlan>(4);
56 planMap.put(plan.constraint, list);
60 planMap.forEachEntry(new TObjectObjectProcedure<CHRConstraint, ArrayList<CHRSearchPlan>>() {
62 public boolean execute(CHRConstraint constraint, ArrayList<CHRSearchPlan> plans) {
63 for(int i=0;i<plans.size();++i)
64 generateActivate(constraint, plans.get(i), i);
68 generateActivate(planMap);
70 classBuilder.getModuleBuilder().addClass(classBuilder);
73 private void generateContructor() {
74 MethodBuilderBase mb = classBuilder.addConstructorBase(Opcodes.ACC_PUBLIC, new TypeDesc[] {storeTypeDesc});
76 mb.loadConstant(rule.priority + ruleset.initialPriorityNumber);
77 mb.invokeSuperConstructor(new TypeDesc[] {TypeDesc.INT});
79 mb.loadLocal(mb.getParameter(0));
80 mb.storeField(containerClassName, "parent", storeTypeDesc);
85 private void generateFields() {
86 classBuilder.addField(Opcodes.ACC_PUBLIC, "parent", storeTypeDesc);
89 // protected abstract void activate(CHRContext context, CHRFact fact);
90 private void generateActivate(THashMap<CHRConstraint, ArrayList<CHRSearchPlan>> planMap) {
92 // public int activate(Object context, int priority) {
96 MethodBuilderBase mb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "activate", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
97 Label finishLabel = mb.createLabel();
99 AtomicReference<Label> nextLabel = new AtomicReference<Label>();
100 planMap.forEachEntry(new TObjectObjectProcedure<CHRConstraint, ArrayList<CHRSearchPlan>>() {
102 public boolean execute(CHRConstraint constraint, ArrayList<CHRSearchPlan> plans) {
103 int nextPriority = ruleset.getAndUpdateNextPriority(constraint, rule.priority);
105 Label next = nextLabel.get();
107 mb.setLocation(next);
108 mb.loadLocal(mb.getParameter(1));
109 mb.instanceOf(constraint.factTypeDesc);
110 next = mb.createLabel();
112 mb.ifZeroComparisonBranch(next, "==");
114 for(int id=0;id<plans.size();++id) {
116 mb.loadLocal(mb.getParameter(0));
117 mb.loadLocal(mb.getParameter(1));
118 mb.checkCast(constraint.factTypeDesc);
119 mb.invokeVirtual(classBuilder.getClassName(), "activate_" + constraint.name + "_" + id, TypeDesc.BOOLEAN, new TypeDesc[] {CHRContext, constraint.factTypeDesc});
120 mb.ifZeroComparisonBranch(finishLabel, "==");
123 // Add to priority queue
124 if(nextPriority != Integer.MAX_VALUE) {
126 mb.loadField(containerClassName, "parent", storeTypeDesc);
127 mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.priorityName(nextPriority), CHRPriorityFactContainer);
128 mb.loadLocal(mb.getParameter(0));
129 mb.loadLocal(mb.getParameter(1));
130 mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
132 else if(constraint.nextContainerFieldName != null && !ruleset.constraintSourceMap.containsKey(constraint)) {
134 mb.loadField(containerClassName, "parent", storeTypeDesc);
135 mb.loadField(storeClassBuilder.getClassName(), constraint.nextContainerFieldName, CHRPriorityFactContainer);
136 LocalVariable containerVar = mb.createLocalVariable("container", CHRPriorityFactContainer);
137 mb.storeLocal(containerVar);
139 mb.loadLocal(containerVar);
140 mb.ifNullBranch(finishLabel, true);
142 mb.loadLocal(containerVar);
143 mb.loadLocal(mb.getParameter(0));
144 mb.loadLocal(mb.getParameter(1));
145 mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
148 mb.branch(finishLabel);
153 Label next = nextLabel.get();
155 mb.setLocation(next);
158 mb.setLocation(finishLabel);
163 // protected abstract void activate(CHRContext context, CHRFact fact);
165 private void generateActivate(CHRConstraint constraint, CHRSearchPlan plan, int id) {
166 MethodBuilder mb = classBuilder.addMethod(Opcodes.ACC_PUBLIC, "activate_" + constraint.name + "_" + id, TypeDesc.BOOLEAN, new TypeDesc[] {CHRContext, constraint.factTypeDesc});
167 LocalVariable priorityVar = new LocalVariable(0, containerTypeDesc);
168 mb.loadLocal(priorityVar);
169 mb.loadField(containerClassName, "parent", storeTypeDesc);
170 LocalVariable parent = mb.createLocalVariable("parent", storeTypeDesc);
171 mb.storeLocal(parent);
172 ruleset.rulesetObject.realizeMethod(mb, (i, target) -> {
173 mb.loadLocal(parent);
174 mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.parameterName(i), ruleset.rulesetObject.parameterTypeDescs[i]);
176 }, plan.implementation, parent, mb.getParameter(0), mb.getParameter(1));