]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRFactCodeGenerator.java
(refs #7250) CHR rules modularization (first working version)
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / chr / CHRFactCodeGenerator.java
1 package org.simantics.scl.compiler.internal.codegen.chr;
2
3 import java.util.ArrayList;
4
5 import org.cojen.classfile.TypeDesc;
6 import org.objectweb.asm.Label;
7 import org.objectweb.asm.Opcodes;
8 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
9 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
10 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint.IndexInfo;
11 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
12 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
13 import org.simantics.scl.compiler.internal.codegen.utils.Constants;
14 import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable;
15 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
16 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
17
18 public class CHRFactCodeGenerator implements CHRCodeGenerationConstants {
19
20     private ModuleBuilder moduleBuilder; 
21     private JavaTypeTranslator jtt;
22
23     private ClassBuilder storeClassBuilder;
24     private CHRRuleset ruleset;
25     private CHRConstraint constraint;
26
27     private String factClassName;
28     private TypeDesc factTypeDesc;
29     private ClassBuilder classBuilder;
30
31     private TypeDesc storeTypeDesc;
32     private TypeDesc[] storeTypeDescArray;
33
34     private TypeDesc[] parameterTypeDescs;
35     private boolean supportsRemoval;
36
37     CHRFactCodeGenerator(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRConstraint constraint) {
38         this.storeClassBuilder = storeClassBuilder;
39         this.ruleset = ruleset;
40         this.constraint = constraint;
41
42         this.moduleBuilder = storeClassBuilder.getModuleBuilder();
43         this.jtt = moduleBuilder.getJavaTypeTranslator();
44         this.storeTypeDesc = storeClassBuilder.getType();
45         this.storeTypeDescArray = new TypeDesc[] { storeTypeDesc };
46
47         this.factClassName = storeClassBuilder.getClassName() + "$" + constraint.name;
48         this.factTypeDesc = TypeDesc.forClass(factClassName);
49         this.classBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, factClassName, CHRFact_name);
50
51         this.parameterTypeDescs = jtt.toTypeDescs(constraint.parameterTypes);
52         this.supportsRemoval = constraint.mayBeRemoved();
53     }
54
55     public void generate(ArrayList<StoreInitialization> hashIndexInitializations) {
56         generateFields(hashIndexInitializations);
57         hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, constraint.name + "$temp", factTypeDesc, factClassName));
58
59         generateIndices();
60         generateAdd();
61
62         if(supportsRemoval)
63             generateRemove();
64
65         generateConstructor();
66         classBuilder.addDefaultConstructor();
67
68         moduleBuilder.addClass(classBuilder);
69     }
70
71     private void generateIndices() {
72         // public ExampleFact ExampleFact$bf(int c0) {
73         //     ExampleFact$temp.c0 = c0;
74         //     return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp);
75         // }
76
77         for(IndexInfo indexInfo : constraint.getIndices()) {
78             if(indexInfo.indexMask != 0) {
79                 ArrayList<TypeDesc> getParameterTypeDescs = new ArrayList<TypeDesc>(constraint.parameterTypes.length);
80                 for(int i=0;i<constraint.parameterTypes.length;++i)
81                     if(((indexInfo.indexMask>>i)&1)==1)
82                         getParameterTypeDescs.add(parameterTypeDescs[i]);
83                 MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, constraint.name + "$" + indexInfo.indexName, factTypeDesc,
84                         getParameterTypeDescs.toArray(new TypeDesc[getParameterTypeDescs.size()]));
85
86                 // ExampleFact$temp.c0 = c0;
87                 mb.loadThis();
88                 mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$temp", factTypeDesc);
89                 LocalVariable tempFactVar = mb.createLocalVariable("temp", factTypeDesc);
90                 mb.storeLocal(tempFactVar);
91                 int parameterId=0;
92                 for(int i=0;i<constraint.parameterTypes.length;++i)
93                     if(((indexInfo.indexMask>>i)&1)==1) {
94                         TypeDesc typeDesc = parameterTypeDescs[i];
95                         if(!typeDesc.equals(TypeDesc.VOID)) {
96                             mb.loadLocal(tempFactVar);
97                             mb.loadLocal(mb.getParameter(parameterId));
98                             mb.storeField(factClassName, CHRCodeGenerationConstants.fieldName(i), typeDesc);
99                         }
100                         ++parameterId;
101                     }
102
103                 // return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp);
104                 mb.loadThis();
105                 mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$" + indexInfo.indexName, CHRHashIndex);
106                 mb.loadLocal(tempFactVar);
107                 mb.invokeVirtual(CHRHashIndex_name, supportsRemoval ? "getEqual" : "getEqualNoRemovals", TypeDesc.OBJECT, Constants.OBJECTS[1]);
108                 mb.checkCast(factTypeDesc);
109                 mb.returnValue(factTypeDesc);
110                 mb.finish();
111             }
112         }   
113     }
114
115     private void generateConstructor() {
116         // public ExampleFact(int id, int c0, int c1) {
117         //     this.id = id;            
118         //     this.c0 = c0;
119         //     this.c1 = c1;
120         // }
121
122         ArrayList<TypeDesc> constructorParameters = new ArrayList<TypeDesc>(parameterTypeDescs.length+1);
123         constructorParameters.add(FACT_ID_TYPE);
124         for(TypeDesc typeDesc : parameterTypeDescs) {
125             if(typeDesc.equals(TypeDesc.VOID))
126                 continue;
127             constructorParameters.add(typeDesc);
128         }
129         MethodBuilderBase mb = classBuilder.addConstructorBase(Opcodes.ACC_PUBLIC, constructorParameters.toArray(new TypeDesc[constructorParameters.size()]));
130         mb.loadThis();
131         mb.invokeConstructor(classBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
132         mb.loadThis();
133         mb.loadLocal(mb.getParameter(0));
134         mb.storeField(CHRFact_name, "id", FACT_ID_TYPE);
135         for(int i=0,parameterId=1;i<constraint.parameterTypes.length;++i) {
136             TypeDesc typeDesc = parameterTypeDescs[i];
137             if(typeDesc.equals(TypeDesc.VOID))
138                 continue;
139             mb.loadThis();
140             mb.loadLocal(mb.getParameter(parameterId++));
141             mb.storeField(factClassName, CHRCodeGenerationConstants.fieldName(i), typeDesc);
142         }
143         mb.returnVoid();
144         mb.finish();
145     }
146
147     private void generateAdd() {
148         MethodBuilderBase mb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "add", TypeDesc.VOID, new TypeDesc[] {storeTypeDesc, CHRContext});
149         LocalVariable storeParameter = mb.getParameter(0);
150         
151         // Add fact to indices
152         for(IndexInfo indexInfo : constraint.getIndices()) {
153             String linkedListPrev = indexInfo.indexName + "Prev";
154             String linkedListNext = indexInfo.indexName + "Next";
155             String storeHashIndexName = constraint.name + "$" + indexInfo.indexName;
156
157             // public void add(ExampleStore store) {
158             //     bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this);
159             //     if(bfNext != null)
160             //         bfNext.bfPrev = this;
161             // }
162
163             if(indexInfo.indexMask == 0) {
164                 mb.loadThis();
165                 mb.loadLocal(storeParameter);
166                 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
167                 if(supportsRemoval)
168                     mb.dupX1();
169                 mb.storeField(factClassName, linkedListNext, factTypeDesc);
170                 if(supportsRemoval) {
171                     Label cont = new Label();
172                     mb.ifNullBranch(cont, true);
173                     mb.loadThis();
174                     mb.loadField(factClassName, linkedListNext, factTypeDesc);
175                     mb.loadThis();
176                     mb.storeField(factClassName, linkedListPrev, factTypeDesc);
177                     mb.setLocation(cont);
178                 }
179                 mb.loadLocal(storeParameter);
180                 mb.loadThis();
181                 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
182             }
183             else {
184                 // bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this);
185                 mb.loadThis();
186                 mb.loadLocal(storeParameter);
187                 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
188                 mb.loadThis();
189                 mb.invokeVirtual(CHRHashIndex_name, supportsRemoval ? "addFreshAndReturnOld" : "addFreshAndReturnOld", TypeDesc.OBJECT, Constants.OBJECTS[1]);
190                 mb.checkCast(factTypeDesc);
191                 if(supportsRemoval)
192                     mb.dupX1();
193                 mb.storeField(factClassName, linkedListNext, factTypeDesc);
194                 // leaves bfNext on the stack
195
196                 //if(bfNext != null)
197                 //    bfNext.bfPrev = this;
198                 if(supportsRemoval) {
199                     Label cont = new Label();
200                     mb.ifNullBranch(cont, true);
201                     mb.loadThis();
202                     mb.loadField(factClassName, linkedListNext, factTypeDesc);
203                     mb.loadThis();
204                     mb.storeField(factClassName, linkedListPrev, factTypeDesc);
205                     mb.setLocation(cont);
206                 }
207             }
208         }
209         
210         // Add fact to priority queue
211         int minimumPriority = ruleset.getMinimumPriority(constraint);
212         if(minimumPriority != Integer.MAX_VALUE) {
213             mb.loadLocal(storeParameter);
214             mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.priorityName(minimumPriority), CHRPriorityFactContainer);
215             mb.loadLocal(mb.getParameter(1));
216             mb.loadThis();
217             mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
218         }
219         else if(constraint.nextContainerFieldName != null) {
220             mb.loadLocal(storeParameter);
221             mb.loadField(storeClassBuilder.getClassName(), constraint.nextContainerFieldName, CHRPriorityFactContainer);
222             LocalVariable containerVar = mb.createLocalVariable("container", CHRPriorityFactContainer);
223             mb.storeLocal(containerVar);
224             
225             mb.loadLocal(containerVar);
226             Label finishLabel = mb.createLabel();
227             mb.ifNullBranch(finishLabel, true);
228             
229             mb.loadLocal(containerVar);
230             mb.loadLocal(mb.getParameter(1));
231             mb.loadThis();
232             mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
233             mb.setLocation(finishLabel);
234         }
235         mb.returnVoid();
236         mb.finish();
237     }
238
239     private void generateFields(ArrayList<StoreInitialization> hashIndexInitializations) {
240         // public int id;
241         // public int c0; // key
242         // public int c1;
243         // public ExampleFact bfPrev;
244         // public ExampleFact bfNext;
245
246         //classBuilder.addField(Opcodes.ACC_PUBLIC, "id", FACT_ID_TYPE);
247         for(int i=0;i<constraint.parameterTypes.length;++i) {
248             TypeDesc typeDesc = parameterTypeDescs[i];
249             if(typeDesc.equals(TypeDesc.VOID))
250                 continue;
251             if(parameterTypeDescs[i] != TypeDesc.VOID)
252                 classBuilder.addField(Opcodes.ACC_PUBLIC, CHRCodeGenerationConstants.fieldName(i), typeDesc);
253         }
254
255         for(IndexInfo indexInfo : constraint.getIndices()) {
256             if(supportsRemoval)
257                 classBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Prev", factTypeDesc);
258             classBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Next", factTypeDesc);
259
260             String hashIndexField = constraint.name + "$" + indexInfo.indexName;
261             if(indexInfo.indexMask == 0) {
262                 // If there are no bound parameters, use just a direct reference to a fact
263                 storeClassBuilder.addField(Opcodes.ACC_PUBLIC, hashIndexField, factTypeDesc);
264             }
265             else {
266                 ClassBuilder hashClass = CHRHashIndexCodeGenerator.generateHashIndex(storeClassBuilder, constraint, indexInfo, factTypeDesc, factClassName);
267                 moduleBuilder.addClass(hashClass);
268                 hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, hashIndexField, CHRHashIndex, hashClass.getClassName()));
269             }
270         }
271     }
272
273     private void generateRemove() {
274         // public void remove(ExampleStore store) {
275         //     if(bfPrev == null) {
276         //         if(bfNext == null)
277         //             store.ExampleFact_bfIndex.removeKnownToExistKey(this);
278         //         else {
279         //             bfNext.bfPrev = null;
280         //             store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext);
281         //         }
282         //     }
283         //     else {
284         //         bfPrev.bfNext = bfNext;
285         //         if(bfNext != null)
286         //             bfNext.bfPrev = bfPrev;
287         //     }
288         // }
289
290         MethodBuilderBase mb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "remove", TypeDesc.VOID, storeTypeDescArray);
291         LocalVariable storeParameter = mb.getParameter(0);
292         for(IndexInfo indexInfo : constraint.getIndices()) {
293             String linkedListPrev = indexInfo.indexName + "Prev";
294             String linkedListNext = indexInfo.indexName + "Next";
295             String storeHashIndexName = constraint.name + "$" + indexInfo.indexName;
296
297             Label nextIndex = mb.createLabel();
298
299             // if(bfPrev == null) {
300             mb.loadThis();
301             mb.loadField(factClassName, linkedListPrev, factTypeDesc);
302             Label else1 = new Label();
303             mb.ifNullBranch(else1, false);
304
305             //     if(bfNext == null)
306             mb.loadThis();
307             mb.loadField(factClassName, linkedListNext, factTypeDesc);
308             Label else2 = new Label();
309             mb.ifNullBranch(else2, false);
310
311             //         store.ExampleFact_bfIndex.removeKnownToExistKey(this);
312             if(indexInfo.indexMask == 0) {
313                 mb.loadLocal(storeParameter);
314                 mb.loadNull();
315                 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
316             }
317             else {
318                 mb.loadLocal(storeParameter);
319                 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
320                 mb.loadThis();
321                 mb.invokeVirtual(CHRHashIndex_name, "removeKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[1]);
322             }
323             mb.branch(nextIndex);
324
325             //     else {
326             mb.setLocation(else2);
327             //         bfNext.bfPrev = null;
328             mb.loadThis();
329             mb.loadField(factClassName, linkedListNext, factTypeDesc);
330             mb.loadNull();
331             mb.storeField(factClassName, linkedListPrev, factTypeDesc);
332             //         store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext);
333             if(indexInfo.indexMask == 0) {
334                 mb.loadLocal(storeParameter);
335                 mb.loadThis();
336                 mb.loadField(factClassName, linkedListNext, factTypeDesc);
337                 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
338             }
339             else {
340                 mb.loadLocal(storeParameter);
341                 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
342                 mb.loadThis();
343                 mb.loadThis();
344                 mb.loadField(factClassName, linkedListNext, factTypeDesc);
345                 mb.invokeVirtual(CHRHashIndex_name, "replaceKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[2]);
346             }
347             mb.branch(nextIndex);
348             //     }
349
350             // else {
351             mb.setLocation(else1);
352             //     bfPrev.bfNext = bfNext;
353             mb.loadThis();
354             mb.loadField(factClassName, linkedListPrev, factTypeDesc);
355             mb.loadThis();
356             mb.loadField(factClassName, linkedListNext, factTypeDesc);
357             mb.storeField(factClassName, linkedListNext, factTypeDesc);
358             //     if(bfNext != null)
359             mb.loadThis();
360             mb.loadField(factClassName, linkedListNext, factTypeDesc);
361             Label else3 = new Label();
362             mb.ifNullBranch(else3, true);
363             //         bfNext.bfPrev = bfPrev;
364             mb.loadThis();
365             mb.loadField(factClassName, linkedListNext, factTypeDesc);
366             mb.loadThis();
367             mb.loadField(factClassName, linkedListPrev, factTypeDesc);
368             mb.storeField(factClassName, linkedListPrev, factTypeDesc);
369             mb.setLocation(else3);
370             mb.branch(nextIndex);
371             // }
372
373             mb.setLocation(nextIndex);
374         }
375         mb.loadThis();
376         mb.loadConstant(-1);
377         mb.storeField(CHRFact_name, "id", FACT_ID_TYPE);
378         mb.returnVoid();
379         mb.finish();
380     }
381 }