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.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;
17 public class CHRFactCodeGenerator implements CHRCodeGenerationConstants {
19 private ModuleBuilder moduleBuilder;
20 private JavaTypeTranslator jtt;
22 private ClassBuilder storeClassBuilder;
23 private CHRConstraint constraint;
25 private String factClassName;
26 private TypeDesc factTypeDesc;
27 private ClassBuilder classBuilder;
29 private TypeDesc storeTypeDesc;
30 private TypeDesc[] storeTypeDescArray;
32 private TypeDesc[] parameterTypeDescs;
33 private boolean supportsRemoval;
35 CHRFactCodeGenerator(ClassBuilder storeClassBuilder, CHRConstraint constraint) {
36 this.storeClassBuilder = storeClassBuilder;
37 this.constraint = constraint;
39 this.moduleBuilder = storeClassBuilder.getModuleBuilder();
40 this.jtt = moduleBuilder.getJavaTypeTranslator();
41 this.storeTypeDesc = storeClassBuilder.getType();
42 this.storeTypeDescArray = new TypeDesc[] { storeTypeDesc };
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);
48 this.parameterTypeDescs = jtt.toTypeDescs(constraint.parameterTypes);
49 this.supportsRemoval = constraint.mayBeRemoved();
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));
62 generateConstructor();
63 classBuilder.addDefaultConstructor();
65 moduleBuilder.addClass(classBuilder);
68 private void generateIndices() {
69 // public ExampleFact ExampleFact$bf(int c0) {
70 // ExampleFact$temp.c0 = c0;
71 // return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp);
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()]));
83 // ExampleFact$temp.c0 = c0;
85 mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$temp", factTypeDesc);
86 LocalVariable tempFactVar = mb.createLocalVariable("temp", factTypeDesc);
87 mb.storeLocal(tempFactVar);
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);
100 // return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp);
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);
112 private void generateConstructor() {
113 // public ExampleFact(int id, int c0, int c1) {
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))
124 constructorParameters.add(typeDesc);
126 MethodBuilderBase mb = classBuilder.addConstructor(Opcodes.ACC_PUBLIC, constructorParameters.toArray(new TypeDesc[constructorParameters.size()]));
128 mb.invokeConstructor(classBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
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))
137 mb.loadLocal(mb.getParameter(parameterId++));
138 mb.storeField(factClassName, CHRCodeGenerationConstants.fieldName(i), typeDesc);
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);
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;
154 // public void add(ExampleStore store) {
155 // bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this);
156 // if(bfNext != null)
157 // bfNext.bfPrev = this;
160 if(indexInfo.indexMask == 0) {
162 mb.loadLocal(storeParameter);
163 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
166 mb.storeField(factClassName, linkedListNext, factTypeDesc);
167 if(supportsRemoval) {
168 Label cont = new Label();
169 mb.ifNullBranch(cont, true);
171 mb.loadField(factClassName, linkedListNext, factTypeDesc);
173 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
174 mb.setLocation(cont);
176 mb.loadLocal(storeParameter);
178 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
181 // bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this);
183 mb.loadLocal(storeParameter);
184 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
186 mb.invokeVirtual(CHRHashIndex_name, supportsRemoval ? "addFreshAndReturnOld" : "addFreshAndReturnOld", TypeDesc.OBJECT, Constants.OBJECTS[1]);
187 mb.checkCast(factTypeDesc);
190 mb.storeField(factClassName, linkedListNext, factTypeDesc);
191 // leaves bfNext on the stack
194 // bfNext.bfPrev = this;
195 if(supportsRemoval) {
196 Label cont = new Label();
197 mb.ifNullBranch(cont, true);
199 mb.loadField(factClassName, linkedListNext, factTypeDesc);
201 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
202 mb.setLocation(cont);
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));
213 mb.invokeVirtual(CHRPriorityFactContainer_name, "addFact", TypeDesc.VOID, new TypeDesc[] {CHRContext, CHRFact});
219 private void generateFields(ArrayList<StoreInitialization> hashIndexInitializations) {
221 // public int c0; // key
223 // public ExampleFact bfPrev;
224 // public ExampleFact bfNext;
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))
231 if(parameterTypeDescs[i] != TypeDesc.VOID)
232 classBuilder.addField(Opcodes.ACC_PUBLIC, CHRCodeGenerationConstants.fieldName(i), typeDesc);
235 for(IndexInfo indexInfo : constraint.getIndices()) {
237 classBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Prev", factTypeDesc);
238 classBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Next", factTypeDesc);
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);
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()));
253 private void generateRemove() {
254 // public void remove(ExampleStore store) {
255 // if(bfPrev == null) {
256 // if(bfNext == null)
257 // store.ExampleFact_bfIndex.removeKnownToExistKey(this);
259 // bfNext.bfPrev = null;
260 // store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext);
264 // bfPrev.bfNext = bfNext;
265 // if(bfNext != null)
266 // bfNext.bfPrev = bfPrev;
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;
277 Label nextIndex = mb.createLabel();
279 // if(bfPrev == null) {
281 mb.loadField(factClassName, linkedListPrev, factTypeDesc);
282 Label else1 = new Label();
283 mb.ifNullBranch(else1, false);
285 // if(bfNext == null)
287 mb.loadField(factClassName, linkedListNext, factTypeDesc);
288 Label else2 = new Label();
289 mb.ifNullBranch(else2, false);
291 // store.ExampleFact_bfIndex.removeKnownToExistKey(this);
292 if(indexInfo.indexMask == 0) {
293 mb.loadLocal(storeParameter);
295 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
298 mb.loadLocal(storeParameter);
299 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
301 mb.invokeVirtual(CHRHashIndex_name, "removeKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[1]);
303 mb.branch(nextIndex);
306 mb.setLocation(else2);
307 // bfNext.bfPrev = null;
309 mb.loadField(factClassName, linkedListNext, factTypeDesc);
311 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
312 // store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext);
313 if(indexInfo.indexMask == 0) {
314 mb.loadLocal(storeParameter);
316 mb.loadField(factClassName, linkedListNext, factTypeDesc);
317 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
320 mb.loadLocal(storeParameter);
321 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
324 mb.loadField(factClassName, linkedListNext, factTypeDesc);
325 mb.invokeVirtual(CHRHashIndex_name, "replaceKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[2]);
327 mb.branch(nextIndex);
331 mb.setLocation(else1);
332 // bfPrev.bfNext = bfNext;
334 mb.loadField(factClassName, linkedListPrev, factTypeDesc);
336 mb.loadField(factClassName, linkedListNext, factTypeDesc);
337 mb.storeField(factClassName, linkedListNext, factTypeDesc);
338 // if(bfNext != null)
340 mb.loadField(factClassName, linkedListNext, factTypeDesc);
341 Label else3 = new Label();
342 mb.ifNullBranch(else3, true);
343 // bfNext.bfPrev = bfPrev;
345 mb.loadField(factClassName, linkedListNext, factTypeDesc);
347 mb.loadField(factClassName, linkedListPrev, factTypeDesc);
348 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
349 mb.setLocation(else3);
350 mb.branch(nextIndex);
353 mb.setLocation(nextIndex);
357 mb.storeField(CHRFact_name, "id", FACT_ID_TYPE);