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