]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRPriorityFactContainerCodeGenerator.java
7ee11f05ec2370e876fa484ae5221319a8ff9b6e
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / chr / CHRPriorityFactContainerCodeGenerator.java
1 package org.simantics.scl.compiler.internal.codegen.chr;
2
3 import java.util.ArrayList;
4 import java.util.concurrent.atomic.AtomicReference;
5
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;
18
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;
23
24 public class CHRPriorityFactContainerCodeGenerator implements CHRCodeGenerationConstants {
25     ClassBuilder storeClassBuilder;
26     String containerClassName;
27     private TypeDesc containerTypeDesc;
28
29     private ClassBuilder classBuilder;
30     
31     private TypeDesc storeTypeDesc;
32     
33     private CHRRuleset ruleset;
34     private CHRRule rule;
35
36     public CHRPriorityFactContainerCodeGenerator(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRRule rule) {
37         this.storeClassBuilder = storeClassBuilder;
38         
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);
42         
43         this.storeTypeDesc = storeClassBuilder.getType();
44         
45         this.ruleset = ruleset;
46         this.rule = rule;
47     }
48     
49     public void generate() {
50         generateFields();
51         generateContructor();
52         
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);
56             if(list == null) {
57                 list = new ArrayList<CHRSearchPlan>(4);
58                 planMap.put(plan.constraint, list);
59             }
60             list.add(plan);
61         }
62         planMap.forEachEntry(new TObjectObjectProcedure<CHRConstraint, ArrayList<CHRSearchPlan>>() {
63             @Override
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);
67                 return true;
68             }
69         });
70         generateActivate(planMap);
71         
72         classBuilder.getModuleBuilder().addClass(classBuilder);
73     }
74     
75     private void generateContructor() {
76         MethodBuilderBase mb = classBuilder.addConstructor(Opcodes.ACC_PUBLIC, new TypeDesc[] {storeTypeDesc});
77         mb.loadThis();
78         mb.loadConstant(rule.priority);
79         mb.invokeSuperConstructor(new TypeDesc[] {TypeDesc.INT});
80         mb.loadThis();
81         mb.loadLocal(mb.getParameter(0));
82         mb.storeField(containerClassName, "parent", storeTypeDesc);
83         mb.returnVoid();
84         mb.finish();
85     }
86     
87     private void generateFields() {
88         classBuilder.addField(Opcodes.ACC_PUBLIC, "parent", storeTypeDesc);
89     }
90
91     // protected abstract void activate(CHRContext context, CHRFact fact);
92     private void generateActivate(THashMap<CHRConstraint, ArrayList<CHRSearchPlan>> planMap) {
93         // @Override
94         // public int activate(Object context, int priority) {
95         //     return -1;
96         // }
97
98         MethodBuilderBase mb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "activate", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
99         Label finishLabel = mb.createLabel();
100
101         AtomicReference<Label> nextLabel = new AtomicReference<Label>();
102         planMap.forEachEntry(new TObjectObjectProcedure<CHRConstraint, ArrayList<CHRSearchPlan>>() {
103             @Override
104             public boolean execute(CHRConstraint constraint, ArrayList<CHRSearchPlan> plans) {
105                 int nextPriority = constraint.nextPriority;
106                 constraint.nextPriority = rule.priority;
107                 
108                 Label next = nextLabel.get();
109                 if(next != null)
110                     mb.setLocation(next);
111                 mb.loadLocal(mb.getParameter(1));
112                 mb.instanceOf(constraint.factTypeDesc);
113                 next = mb.createLabel();
114                 nextLabel.set(next);
115                 mb.ifZeroComparisonBranch(next, "==");
116                 
117                 for(int id=0;id<plans.size();++id) {
118                     mb.loadThis();
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, "==");
124                 }
125                 
126                 // Add to priority queue
127                 if(nextPriority != Integer.MAX_VALUE) {
128                     mb.loadThis();
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});
134                 }
135                 
136                 mb.branch(finishLabel);
137                 return true;
138             }
139         });
140         {
141             Label next = nextLabel.get();
142             if(next != null)
143                 mb.setLocation(next);
144         }
145         
146         mb.setLocation(finishLabel);
147         mb.returnVoid();
148         mb.finish();
149     }
150     
151     private THashSet<BoundVar> usedParameters = new THashSet<BoundVar>();
152
153     // protected abstract void activate(CHRContext context, CHRFact fact);
154
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));
166
167         // Set closure parameters
168         usedParameters.clear();
169         plan.implementation.forValRefs(valRef -> {
170             if(valRef.getBinding() instanceof BoundVar)
171                 usedParameters.add((BoundVar)valRef.getBinding());
172         });
173         for(int j=0;j<ruleset.parameters.length;++j) {
174             BoundVar parameter = ruleset.parameters[j];
175             if(!usedParameters.contains(parameter))
176                 continue;
177             mb.loadLocal(parent);
178             mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.parameterName(j), ruleset.parameterTypeDescs[j]);
179             mb.store(parameter);
180         }
181
182         // Generate code
183         //System.out.println("=== activate" + i + " ==========================================================");
184         //System.out.println(plan.implementation);
185         plan.implementation.markGenerateOnFly();
186         plan.implementation.generateCodeWithAlreadyPreparedParameters(mb);
187         mb.finish();
188     }
189 }