]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRCodeGenerator.java
Merged changes from feature/scl to master.
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / chr / CHRCodeGenerator.java
1 package org.simantics.scl.compiler.internal.codegen.chr;\r
2 \r
3 import java.util.ArrayList;\r
4 \r
5 import org.cojen.classfile.TypeDesc;\r
6 import org.objectweb.asm.Label;\r
7 import org.objectweb.asm.Opcodes;\r
8 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;\r
9 import org.simantics.scl.compiler.elaboration.chr.plan.PrioritizedPlan;\r
10 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;\r
11 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint.IndexInfo;\r
12 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;\r
13 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;\r
14 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;\r
15 import org.simantics.scl.compiler.internal.codegen.utils.CodeBuilderUtils;\r
16 import org.simantics.scl.compiler.internal.codegen.utils.Constants;\r
17 import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable;\r
18 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;\r
19 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;\r
20 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;\r
21 \r
22 import gnu.trove.list.array.TIntArrayList;\r
23 import gnu.trove.set.hash.THashSet;\r
24 \r
25 public class CHRCodeGenerator {\r
26     \r
27     public static final TypeDesc FACT_ID_TYPE = TypeDesc.INT;\r
28     public static final String CHRHashIndex_name = "org/simantics/scl/runtime/chr/CHRHashIndex";\r
29     public static final TypeDesc CHRHashIndex = TypeDesc.forClass(CHRHashIndex_name);\r
30     public static final String FactActivationQueue_name = "org/simantics/scl/runtime/chr/FactActivationQueue";\r
31     public static final TypeDesc FactActivationQueue = TypeDesc.forClass(FactActivationQueue_name);\r
32     public static final String Fact_name = "org/simantics/scl/runtime/chr/Fact";\r
33     public static final TypeDesc Fact = TypeDesc.forClass(Fact_name);\r
34     public static final String QUEUE = "queue";\r
35     \r
36     private static class StoreInitialization {\r
37         final int access;\r
38         final String fieldName;\r
39         final TypeDesc fieldType;\r
40         final String className;\r
41         public StoreInitialization(int access, String fieldName, TypeDesc fieldType, String className) {\r
42             this.access = access;\r
43             this.fieldName = fieldName;\r
44             this.fieldType = fieldType;\r
45             this.className = className;\r
46         }\r
47     }\r
48     \r
49     public static void generateStore(ModuleBuilder moduleBuilder, CHRRuleset ruleset) {\r
50         ClassBuilder storeClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, ruleset.storeClassName, "java/lang/Object");\r
51         if(ruleset.parameters == null)\r
52             ruleset.parameters = new BoundVar[0];\r
53         ruleset.parameterTypeDescs = moduleBuilder.getJavaTypeTranslator().getTypeDescs(ruleset.parameters); \r
54         \r
55         ArrayList<StoreInitialization> hashIndexInitializations = new ArrayList<>();\r
56         for(CHRConstraint constraint : ruleset.constraints)\r
57             generateFact(storeClassBuilder, constraint, hashIndexInitializations);\r
58         \r
59         // Fields\r
60         for(int i=0;i<ruleset.parameterTypeDescs.length;++i)\r
61             storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, "p" + i, ruleset.parameterTypeDescs[i]);\r
62         storeClassBuilder.addField(Opcodes.ACC_PUBLIC, "currentId", FACT_ID_TYPE);\r
63         for(StoreInitialization ini : hashIndexInitializations)\r
64             storeClassBuilder.addField(ini.access, ini.fieldName, ini.fieldType);\r
65         storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, QUEUE, FactActivationQueue);\r
66         \r
67         // Constructors\r
68         \r
69         {\r
70             MethodBuilderBase mb = storeClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, ruleset.parameterTypeDescs);\r
71             mb.loadThis();\r
72             mb.invokeConstructor(storeClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);\r
73             for(int i=0;i<ruleset.parameterTypeDescs.length;++i) {\r
74                 mb.loadThis();\r
75                 mb.loadLocal(mb.getParameter(i));\r
76                 mb.storeField(ruleset.storeClassName, "p" + i, ruleset.parameterTypeDescs[i]);\r
77             }\r
78             mb.loadThis();\r
79             mb.loadConstant(1);\r
80             mb.storeField(storeClassBuilder.getClassName(), "currentId", TypeDesc.INT);\r
81             for(StoreInitialization ini : hashIndexInitializations) {\r
82                 mb.loadThis();\r
83                 mb.newObject(ini.className);\r
84                 mb.dup();\r
85                 mb.invokeConstructor(ini.className, Constants.EMPTY_TYPEDESC_ARRAY);\r
86                 mb.storeField(ruleset.storeClassName, ini.fieldName, ini.fieldType);\r
87             }\r
88             {\r
89                 mb.loadThis();\r
90                 mb.newObject(FactActivationQueue_name);\r
91                 mb.dup();\r
92                 mb.loadConstant(ruleset.priorityCount);\r
93                 mb.invokeConstructor(FactActivationQueue_name, new TypeDesc[] {TypeDesc.INT});\r
94                 mb.storeField(ruleset.storeClassName, QUEUE, FactActivationQueue);\r
95             }\r
96             mb.returnVoid();\r
97             mb.finish();\r
98         }\r
99         \r
100         // Activate\r
101         \r
102         {\r
103             MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "activate", TypeDesc.VOID, new TypeDesc[] {TypeDesc.INT});\r
104             mb.loadThis();\r
105             mb.loadField(ruleset.storeClassName, QUEUE, FactActivationQueue);\r
106             mb.loadThis();\r
107             mb.loadLocal(mb.getParameter(0));\r
108             mb.invokeVirtual(FactActivationQueue_name, "activate", TypeDesc.VOID, new TypeDesc[] {TypeDesc.OBJECT, TypeDesc.INT});\r
109             mb.returnVoid();\r
110             mb.finish();\r
111         }\r
112         \r
113         moduleBuilder.addClass(storeClassBuilder);\r
114     }\r
115     \r
116     private static void generateFact(ClassBuilder storeClassBuilder, CHRConstraint constraint, ArrayList<StoreInitialization> hashIndexInitializations) {\r
117         CHRRuleset ruleset = constraint.parentRuleset;\r
118         boolean supportsRemoval = constraint.mayBeRemoved();\r
119         \r
120         ModuleBuilder moduleBuilder = storeClassBuilder.getModuleBuilder();\r
121         JavaTypeTranslator jtt = moduleBuilder.getJavaTypeTranslator();\r
122         TypeDesc storeTypeDesc = storeClassBuilder.getType();\r
123         TypeDesc[] storeTypeDescArray = new TypeDesc[] { storeTypeDesc };\r
124         \r
125         String factClassName = storeClassBuilder.getClassName() + "$" + constraint.name;\r
126         TypeDesc factTypeDesc = TypeDesc.forClass(factClassName);\r
127         ClassBuilder factClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, factClassName, "java/lang/Object", Fact_name);\r
128         \r
129         // Fields\r
130         \r
131         /* public int id;\r
132            public int c0; // key\r
133            public int c1;\r
134            public ExampleFact bfPrev;\r
135            public ExampleFact bfNext;\r
136          */\r
137         TypeDesc[] parameterTypeDescs = jtt.toTypeDescs(constraint.parameterTypes);\r
138         factClassBuilder.addField(Opcodes.ACC_PUBLIC, "id", FACT_ID_TYPE);\r
139         for(int i=0;i<constraint.parameterTypes.length;++i)\r
140             factClassBuilder.addField(Opcodes.ACC_PUBLIC, "c" + i, parameterTypeDescs[i]);\r
141         \r
142         for(IndexInfo indexInfo : constraint.getIndices()) {\r
143             if(supportsRemoval)\r
144                 factClassBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Prev", factTypeDesc);\r
145             factClassBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Next", factTypeDesc);\r
146             \r
147             String hashIndexField = constraint.name + "$" + indexInfo.indexName;\r
148             if(indexInfo.indexMask == 0) {\r
149                 // If there are now bound parameters, use just a direct reference to a fact\r
150                 storeClassBuilder.addField(Opcodes.ACC_PUBLIC, hashIndexField, factTypeDesc);\r
151             }\r
152             else {\r
153                 ClassBuilder hashClass = generateSpecializedHashIndex(storeClassBuilder, constraint, indexInfo, factTypeDesc, factClassName);\r
154                 moduleBuilder.addClass(hashClass);\r
155                 hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, hashIndexField, CHRHashIndex, hashClass.getClassName()));\r
156             }\r
157         }\r
158         \r
159         // Method: get\r
160         \r
161         hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, constraint.name + "$temp", factTypeDesc, factClassName));\r
162 \r
163         \r
164         {\r
165             /*\r
166             public ExampleFact ExampleFact$bf(int c0) {\r
167                 ExampleFact$temp.c0 = c0;\r
168                 return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp);\r
169             }\r
170             */\r
171             for(IndexInfo indexInfo : constraint.getIndices()) {\r
172                 /*if(indexInfo.indexMask == 0) {\r
173                     MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, constraint.name + "$" + indexInfo.indexName,\r
174                             factTypeDesc, Constants.EMPTY_TYPEDESC_ARRAY);\r
175                     mb.loadThis();\r
176                     mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$" + indexInfo.indexName, factTypeDesc);\r
177                     mb.returnValue(factTypeDesc);\r
178                     mb.finish();\r
179                 }*/\r
180                 if(indexInfo.indexMask != 0) {\r
181                     ArrayList<TypeDesc> getParameterTypeDescs = new ArrayList<TypeDesc>(constraint.parameterTypes.length);\r
182                     for(int i=0;i<constraint.parameterTypes.length;++i)\r
183                         if(((indexInfo.indexMask>>i)&1)==1)\r
184                             getParameterTypeDescs.add(parameterTypeDescs[i]);\r
185                     MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, constraint.name + "$" + indexInfo.indexName, factTypeDesc,\r
186                             getParameterTypeDescs.toArray(new TypeDesc[getParameterTypeDescs.size()]));\r
187                     mb.loadThis();\r
188                     mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$temp", factTypeDesc);\r
189                     LocalVariable tempFactVar = mb.createLocalVariable("temp", factTypeDesc);\r
190                     mb.storeLocal(tempFactVar);\r
191                     int parameterId=0;\r
192                     for(int i=0;i<constraint.parameterTypes.length;++i)\r
193                         if(((indexInfo.indexMask>>i)&1)==1) {\r
194                             mb.loadLocal(tempFactVar);\r
195                             mb.loadLocal(mb.getParameter(parameterId++));\r
196                             mb.storeField(factClassName, "c"+i, parameterTypeDescs[i]);\r
197                         }\r
198 \r
199                     mb.loadThis();\r
200                     mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$" + indexInfo.indexName, CHRHashIndex);\r
201                     mb.loadLocal(tempFactVar);\r
202                     mb.invokeVirtual(CHRHashIndex_name, supportsRemoval ? "getEqual" : "getEqualNoRemovals", TypeDesc.OBJECT, Constants.OBJECTS[1]);\r
203                     mb.checkCast(factTypeDesc);\r
204                 \r
205                     mb.returnValue(factTypeDesc);\r
206                     mb.finish();\r
207                 }\r
208             }   \r
209         }\r
210         \r
211         // Method: add\r
212         \r
213         {\r
214             MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "add", TypeDesc.VOID, storeTypeDescArray);\r
215             LocalVariable storeParameter = mb.getParameter(0);\r
216             for(IndexInfo indexInfo : constraint.getIndices()) {\r
217                 String linkedListPrev = indexInfo.indexName + "Prev";\r
218                 String linkedListNext = indexInfo.indexName + "Next";\r
219                 String storeHashIndexName = constraint.name + "$" + indexInfo.indexName;\r
220                 \r
221                 // public void add(ExampleStore store) {\r
222                 //     bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this);\r
223                 //     if(bfNext != null)\r
224                 //         bfNext.bfPrev = this;\r
225                 // }\r
226                 \r
227                 if(indexInfo.indexMask == 0) {\r
228                     mb.loadThis();\r
229                     mb.loadLocal(storeParameter);\r
230                     mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);\r
231                     if(supportsRemoval)\r
232                         mb.dupX1();\r
233                     mb.storeField(factClassName, linkedListNext, factTypeDesc);\r
234                     if(supportsRemoval) {\r
235                         Label cont = new Label();\r
236                         mb.ifNullBranch(cont, true);\r
237                         mb.loadThis();\r
238                         mb.loadField(factClassName, linkedListNext, factTypeDesc);\r
239                         mb.loadThis();\r
240                         mb.storeField(factClassName, linkedListPrev, factTypeDesc);\r
241                         mb.setLocation(cont);\r
242                     }\r
243                     mb.loadLocal(storeParameter);\r
244                     mb.loadThis();\r
245                     mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);\r
246                 }\r
247                 else {\r
248                     // bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this);\r
249                     mb.loadThis();\r
250                     mb.loadLocal(storeParameter);\r
251                     mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);\r
252                     mb.loadThis();\r
253                     mb.invokeVirtual(CHRHashIndex_name, supportsRemoval ? "addFreshAndReturnOld" : "addFreshAndReturnOld", TypeDesc.OBJECT, Constants.OBJECTS[1]);\r
254                     mb.checkCast(factTypeDesc);\r
255                     if(supportsRemoval)\r
256                         mb.dupX1();\r
257                     mb.storeField(factClassName, linkedListNext, factTypeDesc);\r
258                     // leaves bfNext on the stack\r
259 \r
260                     //if(bfNext != null)\r
261                     //    bfNext.bfPrev = this;\r
262                     if(supportsRemoval) {\r
263                         Label cont = new Label();\r
264                         mb.ifNullBranch(cont, true);\r
265                         mb.loadThis();\r
266                         mb.loadField(factClassName, linkedListNext, factTypeDesc);\r
267                         mb.loadThis();\r
268                         mb.storeField(factClassName, linkedListPrev, factTypeDesc);\r
269                         mb.setLocation(cont);\r
270                     }\r
271                 }\r
272             }            \r
273             if(!constraint.isPassive()) {\r
274                 mb.loadLocal(storeParameter);\r
275                 mb.loadField(storeClassBuilder.getClassName(), QUEUE, FactActivationQueue);\r
276                 mb.loadConstant(constraint.getMinimumPriority());\r
277                 mb.loadThis();\r
278                 mb.invokeVirtual(FactActivationQueue_name, "add", TypeDesc.VOID, new TypeDesc[] {TypeDesc.INT, Fact});\r
279             }\r
280             mb.returnVoid();\r
281             mb.finish();\r
282         }\r
283         \r
284         // Method: remove\r
285 \r
286         if(supportsRemoval) {\r
287             // public void remove(ExampleStore store) {\r
288             //     if(bfPrev == null) {\r
289             //         if(bfNext == null)\r
290             //             store.ExampleFact_bfIndex.removeKnownToExistKey(this);\r
291             //         else {\r
292             //             bfNext.bfPrev = null;\r
293             //             store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext);\r
294             //         }\r
295             //     }\r
296             //     else {\r
297             //         bfPrev.bfNext = bfNext;\r
298             //         if(bfNext != null)\r
299             //             bfNext.bfPrev = bfPrev;\r
300             //     }\r
301             // }\r
302             \r
303             MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "remove", TypeDesc.VOID, storeTypeDescArray);\r
304             LocalVariable storeParameter = mb.getParameter(0);\r
305             for(IndexInfo indexInfo : constraint.getIndices()) {\r
306                 String linkedListPrev = indexInfo.indexName + "Prev";\r
307                 String linkedListNext = indexInfo.indexName + "Next";\r
308                 String storeHashIndexName = constraint.name + "$" + indexInfo.indexName;\r
309                 \r
310                 Label nextIndex = mb.createLabel();\r
311                 \r
312                 // if(bfPrev == null) {\r
313                 mb.loadThis();\r
314                 mb.loadField(factClassName, linkedListPrev, factTypeDesc);\r
315                 Label else1 = new Label();\r
316                 mb.ifNullBranch(else1, false);\r
317                 \r
318                 //     if(bfNext == null)\r
319                 mb.loadThis();\r
320                 mb.loadField(factClassName, linkedListNext, factTypeDesc);\r
321                 Label else2 = new Label();\r
322                 mb.ifNullBranch(else2, false);\r
323                 \r
324                 //         store.ExampleFact_bfIndex.removeKnownToExistKey(this);\r
325                 if(indexInfo.indexMask == 0) {\r
326                     mb.loadLocal(storeParameter);\r
327                     mb.loadNull();\r
328                     mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);\r
329                 }\r
330                 else {\r
331                     mb.loadLocal(storeParameter);\r
332                     mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);\r
333                     mb.loadThis();\r
334                     mb.invokeVirtual(CHRHashIndex_name, "removeKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[1]);\r
335                 }\r
336                 mb.branch(nextIndex);\r
337                 \r
338                 //     else {\r
339                 mb.setLocation(else2);\r
340                 //         bfNext.bfPrev = null;\r
341                 mb.loadThis();\r
342                 mb.loadField(factClassName, linkedListNext, factTypeDesc);\r
343                 mb.loadNull();\r
344                 mb.storeField(factClassName, linkedListPrev, factTypeDesc);\r
345                 //         store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext);\r
346                 if(indexInfo.indexMask == 0) {\r
347                     mb.loadLocal(storeParameter);\r
348                     mb.loadThis();\r
349                     mb.loadField(factClassName, linkedListNext, factTypeDesc);\r
350                     mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);\r
351                 }\r
352                 else {\r
353                     mb.loadLocal(storeParameter);\r
354                     mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);\r
355                     mb.loadThis();\r
356                     mb.loadThis();\r
357                     mb.loadField(factClassName, linkedListNext, factTypeDesc);\r
358                     mb.invokeVirtual(CHRHashIndex_name, "replaceKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[2]);\r
359                 }\r
360                 mb.branch(nextIndex);\r
361                 //     }\r
362                 \r
363                 // else {\r
364                 mb.setLocation(else1);\r
365                 //     bfPrev.bfNext = bfNext;\r
366                 mb.loadThis();\r
367                 mb.loadField(factClassName, linkedListPrev, factTypeDesc);\r
368                 mb.loadThis();\r
369                 mb.loadField(factClassName, linkedListNext, factTypeDesc);\r
370                 mb.storeField(factClassName, linkedListNext, factTypeDesc);\r
371                 //     if(bfNext != null)\r
372                 mb.loadThis();\r
373                 mb.loadField(factClassName, linkedListNext, factTypeDesc);\r
374                 Label else3 = new Label();\r
375                 mb.ifNullBranch(else3, true);\r
376                 //         bfNext.bfPrev = bfPrev;\r
377                 mb.loadThis();\r
378                 mb.loadField(factClassName, linkedListNext, factTypeDesc);\r
379                 mb.loadThis();\r
380                 mb.loadField(factClassName, linkedListPrev, factTypeDesc);\r
381                 mb.storeField(factClassName, linkedListPrev, factTypeDesc);\r
382                 mb.setLocation(else3);\r
383                 mb.branch(nextIndex);\r
384                 // }\r
385                 \r
386                 mb.setLocation(nextIndex);\r
387             }\r
388             mb.loadThis();\r
389             mb.loadConstant(-1);\r
390             mb.storeField(factClassName, "id", FACT_ID_TYPE);\r
391             mb.returnVoid();\r
392             mb.finish();\r
393         }\r
394         \r
395         // Method: isAlive\r
396 \r
397         {\r
398             // @Override\r
399             // public boolean isAlive() {\r
400             //     return id >= 0;\r
401             // }\r
402             \r
403             MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "isAlive", TypeDesc.BOOLEAN, Constants.EMPTY_TYPEDESC_ARRAY);\r
404             if(supportsRemoval) {\r
405                 mb.loadThis();\r
406                 mb.loadField(factClassName, "id", FACT_ID_TYPE);\r
407 \r
408                 Label thenBranch = mb.createLabel();\r
409                 mb.ifZeroComparisonBranch(thenBranch, "<");\r
410                 mb.loadConstant(true);\r
411                 mb.returnValue(TypeDesc.BOOLEAN);\r
412 \r
413                 mb.setLocation(thenBranch);\r
414                 mb.loadConstant(false);\r
415                 mb.returnValue(TypeDesc.BOOLEAN);\r
416             }\r
417             else {\r
418                 mb.loadConstant(true);\r
419                 mb.returnValue(TypeDesc.BOOLEAN);\r
420             }\r
421             mb.finish();\r
422         }\r
423         \r
424         // activate parts\r
425         \r
426         THashSet<BoundVar> usedParameters = new THashSet<BoundVar>();\r
427         for(int i=0;i<constraint.plans.size();++i) {\r
428             PrioritizedPlan plan = constraint.plans.get(i);\r
429             MethodBuilder mb = factClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "activate" + i, TypeDesc.BOOLEAN, new TypeDesc[] {storeTypeDesc});\r
430             LocalVariable storeVar = mb.getParameter(0);\r
431             LocalVariable factVar = new LocalVariable(0, factTypeDesc);\r
432             mb.setLocalVariable(ruleset.this_, storeVar);\r
433             mb.setLocalVariable(plan.implementation.getParameters()[0], factVar);\r
434             \r
435             // Set closure parameters\r
436             usedParameters.clear();\r
437             plan.implementation.forValRefs(valRef -> {\r
438                 if(valRef.getBinding() instanceof BoundVar)\r
439                     usedParameters.add((BoundVar)valRef.getBinding());\r
440             });\r
441             for(int j=0;j<ruleset.parameters.length;++j) {\r
442                 BoundVar parameter = ruleset.parameters[j];\r
443                 if(!usedParameters.contains(parameter))\r
444                     continue;\r
445                 mb.loadLocal(storeVar);\r
446                 mb.loadField(storeClassBuilder.getClassName(), "p"+j, ruleset.parameterTypeDescs[j]);\r
447                 mb.store(parameter);\r
448             }\r
449             \r
450             // Generate code\r
451             //System.out.println("=== activate" + i + " ==========================================================");\r
452             //System.out.println(plan.implementation);\r
453             plan.implementation.markGenerateOnFly();\r
454             plan.implementation.generateCodeWithAlreadyPreparedParameters(mb);\r
455             mb.finish();\r
456         }\r
457         \r
458         // Method: activate\r
459 \r
460         {\r
461             // @Override\r
462             // public int activate(Object context, int priority) {\r
463             //     return -1;\r
464             // }\r
465             \r
466             MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "activate", TypeDesc.INT, new TypeDesc[] {TypeDesc.OBJECT, TypeDesc.INT});\r
467             Label defaultLabel = mb.createLabel();\r
468             \r
469             if(!constraint.isPassive()) {\r
470                 // Check if the fact is alive\r
471                 mb.loadThis();\r
472                 mb.loadField(factClassName, "id", TypeDesc.INT);\r
473                 mb.ifZeroComparisonBranch(defaultLabel, "<");\r
474 \r
475                 mb.loadLocal(mb.getParameter(0));\r
476                 mb.checkCast(storeTypeDesc);\r
477                 LocalVariable storeVariable = new LocalVariable(1, storeTypeDesc);\r
478                 mb.storeLocal(storeVariable);\r
479 \r
480                 TIntArrayList priorities = new TIntArrayList(constraint.plans.size());\r
481                 ArrayList<Label> labels = new ArrayList<Label>();\r
482                 int lastPriority = -1;\r
483                 for(PrioritizedPlan plan : constraint.plans)\r
484                     if(plan.priority != lastPriority) {\r
485                         priorities.add(plan.priority);\r
486                         labels.add(mb.createLabel());\r
487                         lastPriority = plan.priority;\r
488                     }\r
489 \r
490                 mb.loadLocal(mb.getParameter(1));\r
491                 mb.switch_(priorities.toArray(), labels.toArray(new Label[labels.size()]), defaultLabel);\r
492                 int labelId = -1;\r
493                 for(int i=0;i<constraint.plans.size();++i) {\r
494                     PrioritizedPlan plan = constraint.plans.get(i);\r
495                     if(labelId == -1 || plan.priority != priorities.get(labelId)) {\r
496                         if(labelId >= 0) {\r
497                             mb.loadConstant(plan.priority);\r
498                             mb.returnValue(TypeDesc.INT);\r
499                         }\r
500                         ++labelId;\r
501                         mb.setLocation(labels.get(labelId));\r
502                     }\r
503                     mb.loadThis();\r
504                     mb.loadLocal(storeVariable);\r
505                     mb.invokeVirtual(factClassName, "activate" + i, TypeDesc.BOOLEAN, new TypeDesc[] {storeTypeDesc});\r
506                     mb.ifZeroComparisonBranch(defaultLabel, "==");\r
507                 }\r
508                 mb.setLocation(defaultLabel);\r
509             }\r
510             mb.loadConstant(-1);\r
511             mb.returnValue(TypeDesc.INT);\r
512             mb.finish();\r
513         }\r
514         \r
515         // Constructors\r
516         \r
517         {\r
518             // public ExampleFact(int id, int c0, int c1) {\r
519             //     this.id = id;            \r
520             //     this.c0 = c0;\r
521             //     this.c1 = c1;\r
522             // }\r
523             \r
524             TypeDesc[] constructorParameters = new TypeDesc[parameterTypeDescs.length+1];\r
525             constructorParameters[0] = FACT_ID_TYPE;\r
526             for(int i=0;i<parameterTypeDescs.length;++i)\r
527                 constructorParameters[i+1] = parameterTypeDescs[i];\r
528             MethodBuilderBase mb = factClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, constructorParameters);\r
529             mb.loadThis();\r
530             mb.invokeConstructor(factClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);\r
531             mb.loadThis();\r
532             mb.loadLocal(mb.getParameter(0));\r
533             mb.storeField(factClassName, "id", FACT_ID_TYPE);\r
534             for(int i=0;i<constraint.parameterTypes.length;++i) {\r
535                 mb.loadThis();\r
536                 mb.loadLocal(mb.getParameter(i+1));\r
537                 mb.storeField(factClassName, "c" + i, parameterTypeDescs[i]);\r
538             }\r
539             mb.returnVoid();\r
540             mb.finish();\r
541         }\r
542         factClassBuilder.addDefaultConstructor();\r
543         \r
544         moduleBuilder.addClass(factClassBuilder);\r
545     }\r
546 \r
547     private static ClassBuilder generateSpecializedHashIndex(ClassBuilder storeClassBuilder, CHRConstraint constraint, IndexInfo indexInfo, TypeDesc factClassTypeDesc, String factClassName) {\r
548         // new CHRHashIndex() {\r
549         //     @Override\r
550         //     protected boolean keyEquals(Object a, Object b) {\r
551         //         return ((ExampleFact)a).c0 == ((ExampleFact)b).c0;\r
552         //     }\r
553         //     @Override\r
554         //     protected int keyHashCode(Object key) {\r
555         //         return ((ExampleFact)key).c0;\r
556         //     }\r
557         // }\r
558 \r
559         ModuleBuilder moduleBuilder = storeClassBuilder.getModuleBuilder();\r
560         JavaTypeTranslator jtt = moduleBuilder.getJavaTypeTranslator();\r
561         \r
562         String hashIndexClassName = factClassName + "$" + indexInfo.indexName; \r
563         ClassBuilder hashIndexClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, hashIndexClassName, "org/simantics/scl/runtime/chr/CHRHashIndex");\r
564         \r
565         // Method: keyEquals\r
566 \r
567         {\r
568 \r
569             // @Override\r
570             // protected boolean keyEquals(Object a, Object b) {\r
571             //     return ((ExampleFact)a).c0 == ((ExampleFact)b).c0;\r
572             // }\r
573             \r
574             MethodBuilderBase mb = hashIndexClassBuilder.addMethodBase(Opcodes.ACC_PROTECTED, "keyEquals", TypeDesc.BOOLEAN, Constants.OBJECTS[2]);\r
575             mb.loadLocal(mb.getParameter(0));\r
576             mb.checkCast(factClassTypeDesc);\r
577             LocalVariable aVar = mb.createLocalVariable("a", factClassTypeDesc);\r
578             mb.storeLocal(aVar);\r
579             \r
580             mb.loadLocal(mb.getParameter(1));\r
581             mb.checkCast(factClassTypeDesc);\r
582             LocalVariable bVar = mb.createLocalVariable("b", factClassTypeDesc);\r
583             mb.storeLocal(bVar);\r
584 \r
585             Label failure = mb.createLabel();\r
586             \r
587             int curMask = indexInfo.indexMask;\r
588             for(int i=0;i<constraint.parameterTypes.length;++i,curMask>>=1)\r
589                 if((curMask&1) == 1) {\r
590                     TypeDesc fieldTypeDesc = jtt.toTypeDesc(constraint.parameterTypes[i]);\r
591                     if(fieldTypeDesc.equals(TypeDesc.VOID))\r
592                         continue;\r
593                     mb.loadLocal(aVar);\r
594                     mb.loadField(factClassName, "c"+i, fieldTypeDesc);\r
595                     \r
596                     mb.loadLocal(bVar);\r
597                     mb.loadField(factClassName, "c"+i, fieldTypeDesc);\r
598 \r
599                     CodeBuilderUtils.equals(mb, fieldTypeDesc, failure);\r
600                 }\r
601             mb.loadConstant(true);\r
602             mb.returnValue(TypeDesc.BOOLEAN);\r
603             \r
604             mb.setLocation(failure);\r
605             mb.loadConstant(false);\r
606             mb.returnValue(TypeDesc.BOOLEAN);\r
607             mb.finish();\r
608         }\r
609         \r
610         // Method: keyHashCode\r
611 \r
612         {\r
613             // @Override\r
614             // protected int keyHashCode(Object key) {\r
615             //     return (0x811C9DC5^((ExampleFact)key).c0)*16777619;\r
616             // }\r
617             \r
618             MethodBuilderBase mb = hashIndexClassBuilder.addMethodBase(Opcodes.ACC_PROTECTED, "keyHashCode", TypeDesc.INT, Constants.OBJECTS[1]);\r
619             mb.loadLocal(mb.getParameter(0));\r
620             mb.checkCast(factClassTypeDesc);\r
621             LocalVariable factVar = mb.createLocalVariable("fact", factClassTypeDesc);\r
622             mb.storeLocal(factVar);\r
623 \r
624             mb.loadConstant(0x811C9DC5);\r
625 \r
626             int curMask = indexInfo.indexMask;\r
627             for(int i=0;i<constraint.parameterTypes.length;++i,curMask>>=1)\r
628                 if((curMask&1) == 1) {\r
629                     TypeDesc fieldTypeDesc = jtt.toTypeDesc(constraint.parameterTypes[i]);\r
630                     if(fieldTypeDesc.equals(TypeDesc.VOID))\r
631                         continue;\r
632                     mb.loadLocal(factVar);\r
633                     mb.loadField(factClassName, "c"+i, fieldTypeDesc);\r
634                     CodeBuilderUtils.hashCode(mb, fieldTypeDesc);\r
635                     mb.math(Opcodes.IXOR);\r
636                     mb.loadConstant(16777619);\r
637                     mb.math(Opcodes.IMUL);\r
638 \r
639                 }\r
640             mb.returnValue(TypeDesc.INT);\r
641             mb.finish();\r
642         }\r
643 \r
644         hashIndexClassBuilder.addDefaultConstructor();\r
645         \r
646         return hashIndexClassBuilder;\r
647     }\r
648 }\r