1 package org.simantics.scl.compiler.internal.codegen.chr;
\r
3 import java.util.ArrayList;
\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
22 import gnu.trove.list.array.TIntArrayList;
\r
23 import gnu.trove.set.hash.THashSet;
\r
25 public class CHRCodeGenerator {
\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
36 private static class StoreInitialization {
\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
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
55 ArrayList<StoreInitialization> hashIndexInitializations = new ArrayList<>();
\r
56 for(CHRConstraint constraint : ruleset.constraints)
\r
57 generateFact(storeClassBuilder, constraint, hashIndexInitializations);
\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
70 MethodBuilderBase mb = storeClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, ruleset.parameterTypeDescs);
\r
72 mb.invokeConstructor(storeClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
\r
73 for(int i=0;i<ruleset.parameterTypeDescs.length;++i) {
\r
75 mb.loadLocal(mb.getParameter(i));
\r
76 mb.storeField(ruleset.storeClassName, "p" + i, ruleset.parameterTypeDescs[i]);
\r
80 mb.storeField(storeClassBuilder.getClassName(), "currentId", TypeDesc.INT);
\r
81 for(StoreInitialization ini : hashIndexInitializations) {
\r
83 mb.newObject(ini.className);
\r
85 mb.invokeConstructor(ini.className, Constants.EMPTY_TYPEDESC_ARRAY);
\r
86 mb.storeField(ruleset.storeClassName, ini.fieldName, ini.fieldType);
\r
90 mb.newObject(FactActivationQueue_name);
\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
103 MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "activate", TypeDesc.VOID, new TypeDesc[] {TypeDesc.INT});
\r
105 mb.loadField(ruleset.storeClassName, QUEUE, FactActivationQueue);
\r
107 mb.loadLocal(mb.getParameter(0));
\r
108 mb.invokeVirtual(FactActivationQueue_name, "activate", TypeDesc.VOID, new TypeDesc[] {TypeDesc.OBJECT, TypeDesc.INT});
\r
113 moduleBuilder.addClass(storeClassBuilder);
\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
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
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
132 public int c0; // key
\r
134 public ExampleFact bfPrev;
\r
135 public ExampleFact bfNext;
\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
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
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
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
161 hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, constraint.name + "$temp", factTypeDesc, factClassName));
\r
166 public ExampleFact ExampleFact$bf(int c0) {
\r
167 ExampleFact$temp.c0 = c0;
\r
168 return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp);
\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
176 mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$" + indexInfo.indexName, factTypeDesc);
\r
177 mb.returnValue(factTypeDesc);
\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
188 mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$temp", factTypeDesc);
\r
189 LocalVariable tempFactVar = mb.createLocalVariable("temp", factTypeDesc);
\r
190 mb.storeLocal(tempFactVar);
\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
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
205 mb.returnValue(factTypeDesc);
\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
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
227 if(indexInfo.indexMask == 0) {
\r
229 mb.loadLocal(storeParameter);
\r
230 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
\r
231 if(supportsRemoval)
\r
233 mb.storeField(factClassName, linkedListNext, factTypeDesc);
\r
234 if(supportsRemoval) {
\r
235 Label cont = new Label();
\r
236 mb.ifNullBranch(cont, true);
\r
238 mb.loadField(factClassName, linkedListNext, factTypeDesc);
\r
240 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
\r
241 mb.setLocation(cont);
\r
243 mb.loadLocal(storeParameter);
\r
245 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
\r
248 // bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this);
\r
250 mb.loadLocal(storeParameter);
\r
251 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
\r
253 mb.invokeVirtual(CHRHashIndex_name, supportsRemoval ? "addFreshAndReturnOld" : "addFreshAndReturnOld", TypeDesc.OBJECT, Constants.OBJECTS[1]);
\r
254 mb.checkCast(factTypeDesc);
\r
255 if(supportsRemoval)
\r
257 mb.storeField(factClassName, linkedListNext, factTypeDesc);
\r
258 // leaves bfNext on the stack
\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
266 mb.loadField(factClassName, linkedListNext, factTypeDesc);
\r
268 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
\r
269 mb.setLocation(cont);
\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
278 mb.invokeVirtual(FactActivationQueue_name, "add", TypeDesc.VOID, new TypeDesc[] {TypeDesc.INT, Fact});
\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
292 // bfNext.bfPrev = null;
\r
293 // store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext);
\r
297 // bfPrev.bfNext = bfNext;
\r
298 // if(bfNext != null)
\r
299 // bfNext.bfPrev = bfPrev;
\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
310 Label nextIndex = mb.createLabel();
\r
312 // if(bfPrev == null) {
\r
314 mb.loadField(factClassName, linkedListPrev, factTypeDesc);
\r
315 Label else1 = new Label();
\r
316 mb.ifNullBranch(else1, false);
\r
318 // if(bfNext == null)
\r
320 mb.loadField(factClassName, linkedListNext, factTypeDesc);
\r
321 Label else2 = new Label();
\r
322 mb.ifNullBranch(else2, false);
\r
324 // store.ExampleFact_bfIndex.removeKnownToExistKey(this);
\r
325 if(indexInfo.indexMask == 0) {
\r
326 mb.loadLocal(storeParameter);
\r
328 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
\r
331 mb.loadLocal(storeParameter);
\r
332 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
\r
334 mb.invokeVirtual(CHRHashIndex_name, "removeKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[1]);
\r
336 mb.branch(nextIndex);
\r
339 mb.setLocation(else2);
\r
340 // bfNext.bfPrev = null;
\r
342 mb.loadField(factClassName, linkedListNext, factTypeDesc);
\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
349 mb.loadField(factClassName, linkedListNext, factTypeDesc);
\r
350 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
\r
353 mb.loadLocal(storeParameter);
\r
354 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
\r
357 mb.loadField(factClassName, linkedListNext, factTypeDesc);
\r
358 mb.invokeVirtual(CHRHashIndex_name, "replaceKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[2]);
\r
360 mb.branch(nextIndex);
\r
364 mb.setLocation(else1);
\r
365 // bfPrev.bfNext = bfNext;
\r
367 mb.loadField(factClassName, linkedListPrev, factTypeDesc);
\r
369 mb.loadField(factClassName, linkedListNext, factTypeDesc);
\r
370 mb.storeField(factClassName, linkedListNext, factTypeDesc);
\r
371 // if(bfNext != null)
\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
378 mb.loadField(factClassName, linkedListNext, factTypeDesc);
\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
386 mb.setLocation(nextIndex);
\r
389 mb.loadConstant(-1);
\r
390 mb.storeField(factClassName, "id", FACT_ID_TYPE);
\r
399 // public boolean isAlive() {
\r
403 MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "isAlive", TypeDesc.BOOLEAN, Constants.EMPTY_TYPEDESC_ARRAY);
\r
404 if(supportsRemoval) {
\r
406 mb.loadField(factClassName, "id", FACT_ID_TYPE);
\r
408 Label thenBranch = mb.createLabel();
\r
409 mb.ifZeroComparisonBranch(thenBranch, "<");
\r
410 mb.loadConstant(true);
\r
411 mb.returnValue(TypeDesc.BOOLEAN);
\r
413 mb.setLocation(thenBranch);
\r
414 mb.loadConstant(false);
\r
415 mb.returnValue(TypeDesc.BOOLEAN);
\r
418 mb.loadConstant(true);
\r
419 mb.returnValue(TypeDesc.BOOLEAN);
\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
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
441 for(int j=0;j<ruleset.parameters.length;++j) {
\r
442 BoundVar parameter = ruleset.parameters[j];
\r
443 if(!usedParameters.contains(parameter))
\r
445 mb.loadLocal(storeVar);
\r
446 mb.loadField(storeClassBuilder.getClassName(), "p"+j, ruleset.parameterTypeDescs[j]);
\r
447 mb.store(parameter);
\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
458 // Method: activate
\r
462 // public int activate(Object context, int priority) {
\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
469 if(!constraint.isPassive()) {
\r
470 // Check if the fact is alive
\r
472 mb.loadField(factClassName, "id", TypeDesc.INT);
\r
473 mb.ifZeroComparisonBranch(defaultLabel, "<");
\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
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
490 mb.loadLocal(mb.getParameter(1));
\r
491 mb.switch_(priorities.toArray(), labels.toArray(new Label[labels.size()]), defaultLabel);
\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
497 mb.loadConstant(plan.priority);
\r
498 mb.returnValue(TypeDesc.INT);
\r
501 mb.setLocation(labels.get(labelId));
\r
504 mb.loadLocal(storeVariable);
\r
505 mb.invokeVirtual(factClassName, "activate" + i, TypeDesc.BOOLEAN, new TypeDesc[] {storeTypeDesc});
\r
506 mb.ifZeroComparisonBranch(defaultLabel, "==");
\r
508 mb.setLocation(defaultLabel);
\r
510 mb.loadConstant(-1);
\r
511 mb.returnValue(TypeDesc.INT);
\r
518 // public ExampleFact(int id, int c0, int c1) {
\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
530 mb.invokeConstructor(factClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
\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
536 mb.loadLocal(mb.getParameter(i+1));
\r
537 mb.storeField(factClassName, "c" + i, parameterTypeDescs[i]);
\r
542 factClassBuilder.addDefaultConstructor();
\r
544 moduleBuilder.addClass(factClassBuilder);
\r
547 private static ClassBuilder generateSpecializedHashIndex(ClassBuilder storeClassBuilder, CHRConstraint constraint, IndexInfo indexInfo, TypeDesc factClassTypeDesc, String factClassName) {
\r
548 // new CHRHashIndex() {
\r
550 // protected boolean keyEquals(Object a, Object b) {
\r
551 // return ((ExampleFact)a).c0 == ((ExampleFact)b).c0;
\r
554 // protected int keyHashCode(Object key) {
\r
555 // return ((ExampleFact)key).c0;
\r
559 ModuleBuilder moduleBuilder = storeClassBuilder.getModuleBuilder();
\r
560 JavaTypeTranslator jtt = moduleBuilder.getJavaTypeTranslator();
\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
565 // Method: keyEquals
\r
570 // protected boolean keyEquals(Object a, Object b) {
\r
571 // return ((ExampleFact)a).c0 == ((ExampleFact)b).c0;
\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
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
585 Label failure = mb.createLabel();
\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
593 mb.loadLocal(aVar);
\r
594 mb.loadField(factClassName, "c"+i, fieldTypeDesc);
\r
596 mb.loadLocal(bVar);
\r
597 mb.loadField(factClassName, "c"+i, fieldTypeDesc);
\r
599 CodeBuilderUtils.equals(mb, fieldTypeDesc, failure);
\r
601 mb.loadConstant(true);
\r
602 mb.returnValue(TypeDesc.BOOLEAN);
\r
604 mb.setLocation(failure);
\r
605 mb.loadConstant(false);
\r
606 mb.returnValue(TypeDesc.BOOLEAN);
\r
610 // Method: keyHashCode
\r
614 // protected int keyHashCode(Object key) {
\r
615 // return (0x811C9DC5^((ExampleFact)key).c0)*16777619;
\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
624 mb.loadConstant(0x811C9DC5);
\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
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
640 mb.returnValue(TypeDesc.INT);
\r
644 hashIndexClassBuilder.addDefaultConstructor();
\r
646 return hashIndexClassBuilder;
\r