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.elaboration.chr.CHRRule;
10 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
11 import org.simantics.scl.compiler.elaboration.chr.plan.CHRSearchPlan;
12 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
13 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
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.impl.PrimeFinder;
20 import gnu.trove.map.hash.THashMap;
21 import gnu.trove.procedure.TObjectObjectProcedure;
22 import gnu.trove.set.hash.THashSet;
24 public class CHRPriorityFactContainerCodeGenerator implements CHRCodeGenerationConstants {
25 ClassBuilder storeClassBuilder;
26 String containerClassName;
27 private TypeDesc containerTypeDesc;
29 private ClassBuilder classBuilder;
31 private TypeDesc storeTypeDesc;
33 private CHRRuleset ruleset;
36 public CHRPriorityFactContainerCodeGenerator(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRRule rule) {
37 this.storeClassBuilder = storeClassBuilder;
39 this.containerClassName = storeClassBuilder.getClassName() + "$" + "CHRPriorityFactContainer" + rule.priority;
40 this.containerTypeDesc = TypeDesc.forClass(containerClassName);
41 this.classBuilder = new ClassBuilder(storeClassBuilder.getModuleBuilder(), Opcodes.ACC_PUBLIC, containerClassName, CHRPriorityFactContainer_name);
43 this.storeTypeDesc = storeClassBuilder.getType();
45 this.ruleset = ruleset;
49 public void generate() {
53 THashMap<CHRConstraint, ArrayList<CHRSearchPlan>> planMap = new THashMap<CHRConstraint, ArrayList<CHRSearchPlan>>();
54 for(CHRSearchPlan plan : rule.plans) {
55 ArrayList<CHRSearchPlan> list = planMap.get(plan.constraint);
57 list = new ArrayList<CHRSearchPlan>(4);
58 planMap.put(plan.constraint, list);
62 planMap.forEachEntry(new TObjectObjectProcedure<CHRConstraint, ArrayList<CHRSearchPlan>>() {
64 public boolean execute(CHRConstraint constraint, ArrayList<CHRSearchPlan> plans) {
65 for(int i=0;i<plans.size();++i)
66 generateActivate(constraint, plans.get(i), i);
70 generateActivate(planMap);
72 classBuilder.getModuleBuilder().addClass(classBuilder);
75 private void generateContructor() {
76 MethodBuilderBase mb = classBuilder.addConstructor(Opcodes.ACC_PUBLIC, new TypeDesc[] {storeTypeDesc});
78 mb.loadConstant(rule.priority);
79 mb.invokeSuperConstructor(new TypeDesc[] {TypeDesc.INT});
81 mb.loadLocal(mb.getParameter(0));
82 mb.storeField(containerClassName, "parent", storeTypeDesc);
87 private void generateFields() {
88 classBuilder.addField(Opcodes.ACC_PUBLIC, "parent", storeTypeDesc);
91 // protected abstract void activate(CHRContext context, CHRFact fact);
92 private void generateActivate(THashMap<CHRConstraint, ArrayList<CHRSearchPlan>> planMap) {
94 // public int activate(Object context, int priority) {
98 MethodBuilderBase mb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "activate", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
99 Label finishLabel = mb.createLabel();
101 AtomicReference<Label> nextLabel = new AtomicReference<Label>();
102 planMap.forEachEntry(new TObjectObjectProcedure<CHRConstraint, ArrayList<CHRSearchPlan>>() {
104 public boolean execute(CHRConstraint constraint, ArrayList<CHRSearchPlan> plans) {
105 int nextPriority = constraint.nextPriority;
106 constraint.nextPriority = rule.priority;
108 Label next = nextLabel.get();
110 mb.setLocation(next);
111 mb.loadLocal(mb.getParameter(1));
112 mb.instanceOf(constraint.factTypeDesc);
113 next = mb.createLabel();
115 mb.ifZeroComparisonBranch(next, "==");
117 for(int id=0;id<plans.size();++id) {
119 mb.loadLocal(mb.getParameter(0));
120 mb.loadLocal(mb.getParameter(1));
121 mb.checkCast(constraint.factTypeDesc);
122 mb.invokeVirtual(classBuilder.getClassName(), "activate_" + constraint.name + "_" + id, TypeDesc.BOOLEAN, new TypeDesc[] {CHRContext, constraint.factTypeDesc});
123 mb.ifZeroComparisonBranch(finishLabel, "==");
126 // Add to priority queue
127 if(nextPriority != Integer.MAX_VALUE) {
129 mb.loadField(containerClassName, "parent", storeTypeDesc);
130 mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.priorityName(nextPriority), CHRPriorityFactContainer);
131 mb.loadLocal(mb.getParameter(0));
132 mb.loadLocal(mb.getParameter(1));
133 mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
136 mb.branch(finishLabel);
141 Label next = nextLabel.get();
143 mb.setLocation(next);
146 mb.setLocation(finishLabel);
151 private THashSet<BoundVar> usedParameters = new THashSet<BoundVar>();
153 // protected abstract void activate(CHRContext context, CHRFact fact);
155 private void generateActivate(CHRConstraint constraint, CHRSearchPlan plan, int id) {
156 MethodBuilder mb = classBuilder.addMethod(Opcodes.ACC_PUBLIC, "activate_" + constraint.name + "_" + id, TypeDesc.BOOLEAN, new TypeDesc[] {CHRContext, constraint.factTypeDesc});
157 LocalVariable priorityVar = new LocalVariable(0, containerTypeDesc);
158 mb.loadLocal(priorityVar);
159 mb.loadField(containerClassName, "parent", storeTypeDesc);
160 LocalVariable parent = mb.createLocalVariable("parent", storeTypeDesc);
161 mb.storeLocal(parent);
162 BoundVar[] implementationParameters = plan.implementation.getParameters();
163 mb.setLocalVariable(ruleset.this_, parent);
164 mb.setLocalVariable(implementationParameters[0], mb.getParameter(0));
165 mb.setLocalVariable(implementationParameters[1], mb.getParameter(1));
167 // Set closure parameters
168 usedParameters.clear();
169 plan.implementation.forValRefs(valRef -> {
170 if(valRef.getBinding() instanceof BoundVar)
171 usedParameters.add((BoundVar)valRef.getBinding());
173 for(int j=0;j<ruleset.parameters.length;++j) {
174 BoundVar parameter = ruleset.parameters[j];
175 if(!usedParameters.contains(parameter))
177 mb.loadLocal(parent);
178 mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.parameterName(j), ruleset.parameterTypeDescs[j]);
183 //System.out.println("=== activate" + i + " ==========================================================");
184 //System.out.println(plan.implementation);
185 plan.implementation.markGenerateOnFly();
186 plan.implementation.generateCodeWithAlreadyPreparedParameters(mb);