1 package org.simantics.scl.compiler.internal.codegen.chr;
3 import java.util.ArrayList;
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;
18 public class CHRFactCodeGenerator implements CHRCodeGenerationConstants {
20 private ModuleBuilder moduleBuilder;
21 private JavaTypeTranslator jtt;
23 private ClassBuilder storeClassBuilder;
24 private CHRRuleset ruleset;
25 private CHRConstraint constraint;
27 private String factClassName;
28 private TypeDesc factTypeDesc;
29 private ClassBuilder classBuilder;
31 private TypeDesc storeTypeDesc;
32 private TypeDesc[] storeTypeDescArray;
34 private TypeDesc[] parameterTypeDescs;
35 private boolean supportsRemoval;
37 CHRFactCodeGenerator(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRConstraint constraint) {
38 this.storeClassBuilder = storeClassBuilder;
39 this.ruleset = ruleset;
40 this.constraint = constraint;
42 this.moduleBuilder = storeClassBuilder.getModuleBuilder();
43 this.jtt = moduleBuilder.getJavaTypeTranslator();
44 this.storeTypeDesc = storeClassBuilder.getType();
45 this.storeTypeDescArray = new TypeDesc[] { storeTypeDesc };
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);
51 this.parameterTypeDescs = jtt.toTypeDescs(constraint.parameterTypes);
52 this.supportsRemoval = constraint.mayBeRemoved();
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));
65 generateConstructor();
66 classBuilder.addDefaultConstructor();
68 moduleBuilder.addClass(classBuilder);
71 private void generateIndices() {
72 // public ExampleFact ExampleFact$bf(int c0) {
73 // ExampleFact$temp.c0 = c0;
74 // return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp);
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()]));
86 // ExampleFact$temp.c0 = c0;
88 mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$temp", factTypeDesc);
89 LocalVariable tempFactVar = mb.createLocalVariable("temp", factTypeDesc);
90 mb.storeLocal(tempFactVar);
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);
103 // return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp);
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);
115 private void generateConstructor() {
116 // public ExampleFact(int id, int c0, int c1) {
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))
127 constructorParameters.add(typeDesc);
129 MethodBuilderBase mb = classBuilder.addConstructorBase(Opcodes.ACC_PUBLIC, constructorParameters.toArray(new TypeDesc[constructorParameters.size()]));
131 mb.invokeConstructor(classBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
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))
140 mb.loadLocal(mb.getParameter(parameterId++));
141 mb.storeField(factClassName, CHRCodeGenerationConstants.fieldName(i), typeDesc);
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);
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;
157 // public void add(ExampleStore store) {
158 // bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this);
159 // if(bfNext != null)
160 // bfNext.bfPrev = this;
163 if(indexInfo.indexMask == 0) {
165 mb.loadLocal(storeParameter);
166 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
169 mb.storeField(factClassName, linkedListNext, factTypeDesc);
170 if(supportsRemoval) {
171 Label cont = new Label();
172 mb.ifNullBranch(cont, true);
174 mb.loadField(factClassName, linkedListNext, factTypeDesc);
176 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
177 mb.setLocation(cont);
179 mb.loadLocal(storeParameter);
181 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
184 // bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this);
186 mb.loadLocal(storeParameter);
187 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
189 mb.invokeVirtual(CHRHashIndex_name, supportsRemoval ? "addFreshAndReturnOld" : "addFreshAndReturnOld", TypeDesc.OBJECT, Constants.OBJECTS[1]);
190 mb.checkCast(factTypeDesc);
193 mb.storeField(factClassName, linkedListNext, factTypeDesc);
194 // leaves bfNext on the stack
197 // bfNext.bfPrev = this;
198 if(supportsRemoval) {
199 Label cont = new Label();
200 mb.ifNullBranch(cont, true);
202 mb.loadField(factClassName, linkedListNext, factTypeDesc);
204 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
205 mb.setLocation(cont);
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));
217 mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
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);
225 mb.loadLocal(containerVar);
226 Label finishLabel = mb.createLabel();
227 mb.ifNullBranch(finishLabel, true);
229 mb.loadLocal(containerVar);
230 mb.loadLocal(mb.getParameter(1));
232 mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
233 mb.setLocation(finishLabel);
239 private void generateFields(ArrayList<StoreInitialization> hashIndexInitializations) {
241 // public int c0; // key
243 // public ExampleFact bfPrev;
244 // public ExampleFact bfNext;
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))
251 if(parameterTypeDescs[i] != TypeDesc.VOID)
252 classBuilder.addField(Opcodes.ACC_PUBLIC, CHRCodeGenerationConstants.fieldName(i), typeDesc);
255 for(IndexInfo indexInfo : constraint.getIndices()) {
257 classBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Prev", factTypeDesc);
258 classBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Next", factTypeDesc);
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);
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()));
273 private void generateRemove() {
274 // public void remove(ExampleStore store) {
275 // if(bfPrev == null) {
276 // if(bfNext == null)
277 // store.ExampleFact_bfIndex.removeKnownToExistKey(this);
279 // bfNext.bfPrev = null;
280 // store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext);
284 // bfPrev.bfNext = bfNext;
285 // if(bfNext != null)
286 // bfNext.bfPrev = bfPrev;
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;
297 Label nextIndex = mb.createLabel();
299 // if(bfPrev == null) {
301 mb.loadField(factClassName, linkedListPrev, factTypeDesc);
302 Label else1 = new Label();
303 mb.ifNullBranch(else1, false);
305 // if(bfNext == null)
307 mb.loadField(factClassName, linkedListNext, factTypeDesc);
308 Label else2 = new Label();
309 mb.ifNullBranch(else2, false);
311 // store.ExampleFact_bfIndex.removeKnownToExistKey(this);
312 if(indexInfo.indexMask == 0) {
313 mb.loadLocal(storeParameter);
315 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
318 mb.loadLocal(storeParameter);
319 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
321 mb.invokeVirtual(CHRHashIndex_name, "removeKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[1]);
323 mb.branch(nextIndex);
326 mb.setLocation(else2);
327 // bfNext.bfPrev = null;
329 mb.loadField(factClassName, linkedListNext, factTypeDesc);
331 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
332 // store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext);
333 if(indexInfo.indexMask == 0) {
334 mb.loadLocal(storeParameter);
336 mb.loadField(factClassName, linkedListNext, factTypeDesc);
337 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
340 mb.loadLocal(storeParameter);
341 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
344 mb.loadField(factClassName, linkedListNext, factTypeDesc);
345 mb.invokeVirtual(CHRHashIndex_name, "replaceKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[2]);
347 mb.branch(nextIndex);
351 mb.setLocation(else1);
352 // bfPrev.bfNext = bfNext;
354 mb.loadField(factClassName, linkedListPrev, factTypeDesc);
356 mb.loadField(factClassName, linkedListNext, factTypeDesc);
357 mb.storeField(factClassName, linkedListNext, factTypeDesc);
358 // if(bfNext != null)
360 mb.loadField(factClassName, linkedListNext, factTypeDesc);
361 Label else3 = new Label();
362 mb.ifNullBranch(else3, true);
363 // bfNext.bfPrev = bfPrev;
365 mb.loadField(factClassName, linkedListNext, factTypeDesc);
367 mb.loadField(factClassName, linkedListPrev, factTypeDesc);
368 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
369 mb.setLocation(else3);
370 mb.branch(nextIndex);
373 mb.setLocation(nextIndex);
377 mb.storeField(CHRFact_name, "id", FACT_ID_TYPE);