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.plan.PrioritizedPlan;
10 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
11 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint.IndexInfo;
12 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
13 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
14 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
15 import org.simantics.scl.compiler.internal.codegen.utils.CodeBuilderUtils;
16 import org.simantics.scl.compiler.internal.codegen.utils.Constants;
17 import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable;
18 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
19 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
20 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
22 import gnu.trove.list.array.TIntArrayList;
23 import gnu.trove.set.hash.THashSet;
25 public class CHRCodeGenerator {
27 public static final TypeDesc FACT_ID_TYPE = TypeDesc.INT;
28 public static final String CHRHashIndex_name = "org/simantics/scl/runtime/chr/CHRHashIndex";
29 public static final TypeDesc CHRHashIndex = TypeDesc.forClass(CHRHashIndex_name);
30 public static final String FactActivationQueue_name = "org/simantics/scl/runtime/chr/FactActivationQueue";
31 public static final TypeDesc FactActivationQueue = TypeDesc.forClass(FactActivationQueue_name);
32 public static final String Fact_name = "org/simantics/scl/runtime/chr/Fact";
33 public static final TypeDesc Fact = TypeDesc.forClass(Fact_name);
34 public static final String QUEUE = "queue";
36 private static class StoreInitialization {
38 final String fieldName;
39 final TypeDesc fieldType;
40 final String className;
41 public StoreInitialization(int access, String fieldName, TypeDesc fieldType, String className) {
43 this.fieldName = fieldName;
44 this.fieldType = fieldType;
45 this.className = className;
49 public static void generateStore(ModuleBuilder moduleBuilder, CHRRuleset ruleset) {
50 ClassBuilder storeClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, ruleset.storeClassName, "java/lang/Object");
51 if(ruleset.parameters == null)
52 ruleset.parameters = new BoundVar[0];
53 ruleset.parameterTypeDescs = moduleBuilder.getJavaTypeTranslator().getTypeDescs(ruleset.parameters);
55 ArrayList<StoreInitialization> hashIndexInitializations = new ArrayList<>();
56 for(CHRConstraint constraint : ruleset.constraints)
57 generateFact(storeClassBuilder, constraint, hashIndexInitializations);
60 for(int i=0;i<ruleset.parameterTypeDescs.length;++i) {
61 TypeDesc typeDesc = ruleset.parameterTypeDescs[i];
62 if(typeDesc.equals(TypeDesc.VOID))
64 storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, "p" + i, typeDesc);
66 storeClassBuilder.addField(Opcodes.ACC_PUBLIC, "currentId", FACT_ID_TYPE);
67 for(StoreInitialization ini : hashIndexInitializations)
68 storeClassBuilder.addField(ini.access, ini.fieldName, ini.fieldType);
69 storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, QUEUE, FactActivationQueue);
74 MethodBuilderBase mb = storeClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, ruleset.parameterTypeDescs);
76 mb.invokeConstructor(storeClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
77 for(int i=0;i<ruleset.parameterTypeDescs.length;++i) {
78 TypeDesc typeDesc = ruleset.parameterTypeDescs[i];
79 if(typeDesc.equals(TypeDesc.VOID))
82 mb.loadLocal(mb.getParameter(i));
83 mb.storeField(ruleset.storeClassName, "p" + i, ruleset.parameterTypeDescs[i]);
87 mb.storeField(storeClassBuilder.getClassName(), "currentId", TypeDesc.INT);
88 for(StoreInitialization ini : hashIndexInitializations) {
90 mb.newObject(ini.className);
92 mb.invokeConstructor(ini.className, Constants.EMPTY_TYPEDESC_ARRAY);
93 mb.storeField(ruleset.storeClassName, ini.fieldName, ini.fieldType);
97 mb.newObject(FactActivationQueue_name);
99 mb.loadConstant(ruleset.priorityCount);
100 mb.invokeConstructor(FactActivationQueue_name, new TypeDesc[] {TypeDesc.INT});
101 mb.storeField(ruleset.storeClassName, QUEUE, FactActivationQueue);
110 MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "activate", TypeDesc.VOID, new TypeDesc[] {TypeDesc.INT});
112 mb.loadField(ruleset.storeClassName, QUEUE, FactActivationQueue);
114 mb.loadLocal(mb.getParameter(0));
115 mb.invokeVirtual(FactActivationQueue_name, "activate", TypeDesc.VOID, new TypeDesc[] {TypeDesc.OBJECT, TypeDesc.INT});
120 moduleBuilder.addClass(storeClassBuilder);
123 private static void generateFact(ClassBuilder storeClassBuilder, CHRConstraint constraint, ArrayList<StoreInitialization> hashIndexInitializations) {
124 CHRRuleset ruleset = constraint.parentRuleset;
125 boolean supportsRemoval = constraint.mayBeRemoved();
127 ModuleBuilder moduleBuilder = storeClassBuilder.getModuleBuilder();
128 JavaTypeTranslator jtt = moduleBuilder.getJavaTypeTranslator();
129 TypeDesc storeTypeDesc = storeClassBuilder.getType();
130 TypeDesc[] storeTypeDescArray = new TypeDesc[] { storeTypeDesc };
132 String factClassName = storeClassBuilder.getClassName() + "$" + constraint.name;
133 TypeDesc factTypeDesc = TypeDesc.forClass(factClassName);
134 ClassBuilder factClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, factClassName, "java/lang/Object", Fact_name);
139 public int c0; // key
141 public ExampleFact bfPrev;
142 public ExampleFact bfNext;
144 TypeDesc[] parameterTypeDescs = jtt.toTypeDescs(constraint.parameterTypes);
145 factClassBuilder.addField(Opcodes.ACC_PUBLIC, "id", FACT_ID_TYPE);
146 for(int i=0;i<constraint.parameterTypes.length;++i) {
147 TypeDesc typeDesc = parameterTypeDescs[i];
148 if(typeDesc.equals(TypeDesc.VOID))
150 if(parameterTypeDescs[i] != TypeDesc.VOID)
151 factClassBuilder.addField(Opcodes.ACC_PUBLIC, fieldName(i), typeDesc);
154 for(IndexInfo indexInfo : constraint.getIndices()) {
156 factClassBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Prev", factTypeDesc);
157 factClassBuilder.addField(Opcodes.ACC_PUBLIC, indexInfo.indexName + "Next", factTypeDesc);
159 String hashIndexField = constraint.name + "$" + indexInfo.indexName;
160 if(indexInfo.indexMask == 0) {
161 // If there are now bound parameters, use just a direct reference to a fact
162 storeClassBuilder.addField(Opcodes.ACC_PUBLIC, hashIndexField, factTypeDesc);
165 ClassBuilder hashClass = generateSpecializedHashIndex(storeClassBuilder, constraint, indexInfo, factTypeDesc, factClassName);
166 moduleBuilder.addClass(hashClass);
167 hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, hashIndexField, CHRHashIndex, hashClass.getClassName()));
173 hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, constraint.name + "$temp", factTypeDesc, factClassName));
178 public ExampleFact ExampleFact$bf(int c0) {
179 ExampleFact$temp.c0 = c0;
180 return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp);
183 for(IndexInfo indexInfo : constraint.getIndices()) {
184 /*if(indexInfo.indexMask == 0) {
185 MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, constraint.name + "$" + indexInfo.indexName,
186 factTypeDesc, Constants.EMPTY_TYPEDESC_ARRAY);
188 mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$" + indexInfo.indexName, factTypeDesc);
189 mb.returnValue(factTypeDesc);
192 if(indexInfo.indexMask != 0) {
193 ArrayList<TypeDesc> getParameterTypeDescs = new ArrayList<TypeDesc>(constraint.parameterTypes.length);
194 for(int i=0;i<constraint.parameterTypes.length;++i)
195 if(((indexInfo.indexMask>>i)&1)==1)
196 getParameterTypeDescs.add(parameterTypeDescs[i]);
197 MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, constraint.name + "$" + indexInfo.indexName, factTypeDesc,
198 getParameterTypeDescs.toArray(new TypeDesc[getParameterTypeDescs.size()]));
200 mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$temp", factTypeDesc);
201 LocalVariable tempFactVar = mb.createLocalVariable("temp", factTypeDesc);
202 mb.storeLocal(tempFactVar);
204 for(int i=0;i<constraint.parameterTypes.length;++i)
205 if(((indexInfo.indexMask>>i)&1)==1) {
206 TypeDesc typeDesc = parameterTypeDescs[i];
207 if(!typeDesc.equals(TypeDesc.VOID)) {
208 mb.loadLocal(tempFactVar);
209 mb.loadLocal(mb.getParameter(parameterId));
210 mb.storeField(factClassName, fieldName(i), typeDesc);
216 mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$" + indexInfo.indexName, CHRHashIndex);
217 mb.loadLocal(tempFactVar);
218 mb.invokeVirtual(CHRHashIndex_name, supportsRemoval ? "getEqual" : "getEqualNoRemovals", TypeDesc.OBJECT, Constants.OBJECTS[1]);
219 mb.checkCast(factTypeDesc);
221 mb.returnValue(factTypeDesc);
230 MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "add", TypeDesc.VOID, storeTypeDescArray);
231 LocalVariable storeParameter = mb.getParameter(0);
232 for(IndexInfo indexInfo : constraint.getIndices()) {
233 String linkedListPrev = indexInfo.indexName + "Prev";
234 String linkedListNext = indexInfo.indexName + "Next";
235 String storeHashIndexName = constraint.name + "$" + indexInfo.indexName;
237 // public void add(ExampleStore store) {
238 // bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this);
239 // if(bfNext != null)
240 // bfNext.bfPrev = this;
243 if(indexInfo.indexMask == 0) {
245 mb.loadLocal(storeParameter);
246 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
249 mb.storeField(factClassName, linkedListNext, factTypeDesc);
250 if(supportsRemoval) {
251 Label cont = new Label();
252 mb.ifNullBranch(cont, true);
254 mb.loadField(factClassName, linkedListNext, factTypeDesc);
256 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
257 mb.setLocation(cont);
259 mb.loadLocal(storeParameter);
261 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
264 // bfNext = (ExampleFact)store.ExampleFact_bfIndex.addFreshAndReturnOld(this);
266 mb.loadLocal(storeParameter);
267 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
269 mb.invokeVirtual(CHRHashIndex_name, supportsRemoval ? "addFreshAndReturnOld" : "addFreshAndReturnOld", TypeDesc.OBJECT, Constants.OBJECTS[1]);
270 mb.checkCast(factTypeDesc);
273 mb.storeField(factClassName, linkedListNext, factTypeDesc);
274 // leaves bfNext on the stack
277 // bfNext.bfPrev = this;
278 if(supportsRemoval) {
279 Label cont = new Label();
280 mb.ifNullBranch(cont, true);
282 mb.loadField(factClassName, linkedListNext, factTypeDesc);
284 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
285 mb.setLocation(cont);
289 if(!constraint.isPassive()) {
290 mb.loadLocal(storeParameter);
291 mb.loadField(storeClassBuilder.getClassName(), QUEUE, FactActivationQueue);
292 mb.loadConstant(constraint.getMinimumPriority());
294 mb.invokeVirtual(FactActivationQueue_name, "add", TypeDesc.VOID, new TypeDesc[] {TypeDesc.INT, Fact});
302 if(supportsRemoval) {
303 // public void remove(ExampleStore store) {
304 // if(bfPrev == null) {
305 // if(bfNext == null)
306 // store.ExampleFact_bfIndex.removeKnownToExistKey(this);
308 // bfNext.bfPrev = null;
309 // store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext);
313 // bfPrev.bfNext = bfNext;
314 // if(bfNext != null)
315 // bfNext.bfPrev = bfPrev;
319 MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "remove", TypeDesc.VOID, storeTypeDescArray);
320 LocalVariable storeParameter = mb.getParameter(0);
321 for(IndexInfo indexInfo : constraint.getIndices()) {
322 String linkedListPrev = indexInfo.indexName + "Prev";
323 String linkedListNext = indexInfo.indexName + "Next";
324 String storeHashIndexName = constraint.name + "$" + indexInfo.indexName;
326 Label nextIndex = mb.createLabel();
328 // if(bfPrev == null) {
330 mb.loadField(factClassName, linkedListPrev, factTypeDesc);
331 Label else1 = new Label();
332 mb.ifNullBranch(else1, false);
334 // if(bfNext == null)
336 mb.loadField(factClassName, linkedListNext, factTypeDesc);
337 Label else2 = new Label();
338 mb.ifNullBranch(else2, false);
340 // store.ExampleFact_bfIndex.removeKnownToExistKey(this);
341 if(indexInfo.indexMask == 0) {
342 mb.loadLocal(storeParameter);
344 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
347 mb.loadLocal(storeParameter);
348 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
350 mb.invokeVirtual(CHRHashIndex_name, "removeKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[1]);
352 mb.branch(nextIndex);
355 mb.setLocation(else2);
356 // bfNext.bfPrev = null;
358 mb.loadField(factClassName, linkedListNext, factTypeDesc);
360 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
361 // store.ExampleFact_bfIndex.replaceKnownToExistKey(this, bfNext);
362 if(indexInfo.indexMask == 0) {
363 mb.loadLocal(storeParameter);
365 mb.loadField(factClassName, linkedListNext, factTypeDesc);
366 mb.storeField(storeClassBuilder.getClassName(), storeHashIndexName, factTypeDesc);
369 mb.loadLocal(storeParameter);
370 mb.loadField(storeClassBuilder.getClassName(), storeHashIndexName, CHRHashIndex);
373 mb.loadField(factClassName, linkedListNext, factTypeDesc);
374 mb.invokeVirtual(CHRHashIndex_name, "replaceKnownToExistKey", TypeDesc.VOID, Constants.OBJECTS[2]);
376 mb.branch(nextIndex);
380 mb.setLocation(else1);
381 // bfPrev.bfNext = bfNext;
383 mb.loadField(factClassName, linkedListPrev, factTypeDesc);
385 mb.loadField(factClassName, linkedListNext, factTypeDesc);
386 mb.storeField(factClassName, linkedListNext, factTypeDesc);
387 // if(bfNext != null)
389 mb.loadField(factClassName, linkedListNext, factTypeDesc);
390 Label else3 = new Label();
391 mb.ifNullBranch(else3, true);
392 // bfNext.bfPrev = bfPrev;
394 mb.loadField(factClassName, linkedListNext, factTypeDesc);
396 mb.loadField(factClassName, linkedListPrev, factTypeDesc);
397 mb.storeField(factClassName, linkedListPrev, factTypeDesc);
398 mb.setLocation(else3);
399 mb.branch(nextIndex);
402 mb.setLocation(nextIndex);
406 mb.storeField(factClassName, "id", FACT_ID_TYPE);
415 // public boolean isAlive() {
419 MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "isAlive", TypeDesc.BOOLEAN, Constants.EMPTY_TYPEDESC_ARRAY);
420 if(supportsRemoval) {
422 mb.loadField(factClassName, "id", FACT_ID_TYPE);
424 Label thenBranch = mb.createLabel();
425 mb.ifZeroComparisonBranch(thenBranch, "<");
426 mb.loadConstant(true);
427 mb.returnValue(TypeDesc.BOOLEAN);
429 mb.setLocation(thenBranch);
430 mb.loadConstant(false);
431 mb.returnValue(TypeDesc.BOOLEAN);
434 mb.loadConstant(true);
435 mb.returnValue(TypeDesc.BOOLEAN);
442 THashSet<BoundVar> usedParameters = new THashSet<BoundVar>();
443 for(int i=0;i<constraint.plans.size();++i) {
444 PrioritizedPlan plan = constraint.plans.get(i);
445 MethodBuilder mb = factClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "activate" + i, TypeDesc.BOOLEAN, new TypeDesc[] {storeTypeDesc});
446 LocalVariable storeVar = mb.getParameter(0);
447 LocalVariable factVar = new LocalVariable(0, factTypeDesc);
448 mb.setLocalVariable(ruleset.this_, storeVar);
449 mb.setLocalVariable(plan.implementation.getParameters()[0], factVar);
451 // Set closure parameters
452 usedParameters.clear();
453 plan.implementation.forValRefs(valRef -> {
454 if(valRef.getBinding() instanceof BoundVar)
455 usedParameters.add((BoundVar)valRef.getBinding());
457 for(int j=0;j<ruleset.parameters.length;++j) {
458 BoundVar parameter = ruleset.parameters[j];
459 if(!usedParameters.contains(parameter))
461 mb.loadLocal(storeVar);
462 mb.loadField(storeClassBuilder.getClassName(), "p"+j, ruleset.parameterTypeDescs[j]);
467 //System.out.println("=== activate" + i + " ==========================================================");
468 //System.out.println(plan.implementation);
469 plan.implementation.markGenerateOnFly();
470 plan.implementation.generateCodeWithAlreadyPreparedParameters(mb);
478 // public int activate(Object context, int priority) {
482 MethodBuilderBase mb = factClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "activate", TypeDesc.INT, new TypeDesc[] {TypeDesc.OBJECT, TypeDesc.INT});
483 Label defaultLabel = mb.createLabel();
485 if(!constraint.isPassive()) {
486 // Check if the fact is alive
488 mb.loadField(factClassName, "id", TypeDesc.INT);
489 mb.ifZeroComparisonBranch(defaultLabel, "<");
491 mb.loadLocal(mb.getParameter(0));
492 mb.checkCast(storeTypeDesc);
493 LocalVariable storeVariable = new LocalVariable(1, storeTypeDesc);
494 mb.storeLocal(storeVariable);
496 TIntArrayList priorities = new TIntArrayList(constraint.plans.size());
497 ArrayList<Label> labels = new ArrayList<Label>();
498 int lastPriority = -1;
499 for(PrioritizedPlan plan : constraint.plans)
500 if(plan.priority != lastPriority) {
501 priorities.add(plan.priority);
502 labels.add(mb.createLabel());
503 lastPriority = plan.priority;
506 mb.loadLocal(mb.getParameter(1));
507 mb.switch_(priorities.toArray(), labels.toArray(new Label[labels.size()]), defaultLabel);
509 for(int i=0;i<constraint.plans.size();++i) {
510 PrioritizedPlan plan = constraint.plans.get(i);
511 if(labelId == -1 || plan.priority != priorities.get(labelId)) {
513 mb.loadConstant(plan.priority);
514 mb.returnValue(TypeDesc.INT);
517 mb.setLocation(labels.get(labelId));
520 mb.loadLocal(storeVariable);
521 mb.invokeVirtual(factClassName, "activate" + i, TypeDesc.BOOLEAN, new TypeDesc[] {storeTypeDesc});
522 mb.ifZeroComparisonBranch(defaultLabel, "==");
524 mb.setLocation(defaultLabel);
527 mb.returnValue(TypeDesc.INT);
534 // public ExampleFact(int id, int c0, int c1) {
540 ArrayList<TypeDesc> constructorParameters = new ArrayList<TypeDesc>(parameterTypeDescs.length+1);
541 constructorParameters.add(FACT_ID_TYPE);
542 for(TypeDesc typeDesc : parameterTypeDescs) {
543 if(typeDesc.equals(TypeDesc.VOID))
545 constructorParameters.add(typeDesc);
547 MethodBuilderBase mb = factClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, constructorParameters.toArray(new TypeDesc[constructorParameters.size()]));
549 mb.invokeConstructor(factClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
551 mb.loadLocal(mb.getParameter(0));
552 mb.storeField(factClassName, "id", FACT_ID_TYPE);
553 for(int i=0,parameterId=1;i<constraint.parameterTypes.length;++i) {
554 TypeDesc typeDesc = parameterTypeDescs[i];
555 if(typeDesc.equals(TypeDesc.VOID))
558 mb.loadLocal(mb.getParameter(parameterId++));
559 mb.storeField(factClassName, fieldName(i), typeDesc);
564 factClassBuilder.addDefaultConstructor();
566 moduleBuilder.addClass(factClassBuilder);
569 private static ClassBuilder generateSpecializedHashIndex(ClassBuilder storeClassBuilder, CHRConstraint constraint, IndexInfo indexInfo, TypeDesc factClassTypeDesc, String factClassName) {
570 // new CHRHashIndex() {
572 // protected boolean keyEquals(Object a, Object b) {
573 // return ((ExampleFact)a).c0 == ((ExampleFact)b).c0;
576 // protected int keyHashCode(Object key) {
577 // return ((ExampleFact)key).c0;
581 ModuleBuilder moduleBuilder = storeClassBuilder.getModuleBuilder();
582 JavaTypeTranslator jtt = moduleBuilder.getJavaTypeTranslator();
584 String hashIndexClassName = factClassName + "$" + indexInfo.indexName;
585 ClassBuilder hashIndexClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, hashIndexClassName, "org/simantics/scl/runtime/chr/CHRHashIndex");
592 // protected boolean keyEquals(Object a, Object b) {
593 // return ((ExampleFact)a).c0 == ((ExampleFact)b).c0;
596 MethodBuilderBase mb = hashIndexClassBuilder.addMethodBase(Opcodes.ACC_PROTECTED, "keyEquals", TypeDesc.BOOLEAN, Constants.OBJECTS[2]);
597 mb.loadLocal(mb.getParameter(0));
598 mb.checkCast(factClassTypeDesc);
599 LocalVariable aVar = mb.createLocalVariable("a", factClassTypeDesc);
602 mb.loadLocal(mb.getParameter(1));
603 mb.checkCast(factClassTypeDesc);
604 LocalVariable bVar = mb.createLocalVariable("b", factClassTypeDesc);
607 Label failure = mb.createLabel();
609 int curMask = indexInfo.indexMask;
610 for(int i=0;i<constraint.parameterTypes.length;++i,curMask>>=1)
611 if((curMask&1) == 1) {
612 TypeDesc fieldTypeDesc = jtt.toTypeDesc(constraint.parameterTypes[i]);
613 if(fieldTypeDesc.equals(TypeDesc.VOID))
616 mb.loadField(factClassName, fieldName(i), fieldTypeDesc);
619 mb.loadField(factClassName, fieldName(i), fieldTypeDesc);
621 CodeBuilderUtils.equals(mb, fieldTypeDesc, failure);
623 mb.loadConstant(true);
624 mb.returnValue(TypeDesc.BOOLEAN);
626 mb.setLocation(failure);
627 mb.loadConstant(false);
628 mb.returnValue(TypeDesc.BOOLEAN);
632 // Method: keyHashCode
636 // protected int keyHashCode(Object key) {
637 // return (0x811C9DC5^((ExampleFact)key).c0)*16777619;
640 MethodBuilderBase mb = hashIndexClassBuilder.addMethodBase(Opcodes.ACC_PROTECTED, "keyHashCode", TypeDesc.INT, Constants.OBJECTS[1]);
641 mb.loadLocal(mb.getParameter(0));
642 mb.checkCast(factClassTypeDesc);
643 LocalVariable factVar = mb.createLocalVariable("fact", factClassTypeDesc);
644 mb.storeLocal(factVar);
646 mb.loadConstant(0x811C9DC5);
648 int curMask = indexInfo.indexMask;
649 for(int i=0;i<constraint.parameterTypes.length;++i,curMask>>=1)
650 if((curMask&1) == 1) {
651 TypeDesc fieldTypeDesc = jtt.toTypeDesc(constraint.parameterTypes[i]);
652 if(fieldTypeDesc.equals(TypeDesc.VOID))
654 mb.loadLocal(factVar);
655 mb.loadField(factClassName, fieldName(i), fieldTypeDesc);
656 CodeBuilderUtils.hashCode(mb, fieldTypeDesc);
657 mb.math(Opcodes.IXOR);
658 mb.loadConstant(16777619);
659 mb.math(Opcodes.IMUL);
662 mb.returnValue(TypeDesc.INT);
666 hashIndexClassBuilder.addDefaultConstructor();
668 return hashIndexClassBuilder;
671 public static String fieldName(int id) {