package org.simantics.scl.compiler.internal.codegen.chr; import java.util.ArrayList; import org.cojen.classfile.TypeDesc; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.simantics.scl.compiler.elaboration.chr.CHRRuleset; import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint; import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint.IndexInfo; import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator; import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder; import org.simantics.scl.compiler.internal.codegen.utils.Constants; import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable; import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase; import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder; public class CHRFactCodeGenerator implements CHRCodeGenerationConstants { private ModuleBuilder moduleBuilder; private JavaTypeTranslator jtt; private ClassBuilder storeClassBuilder; private CHRRuleset ruleset; private CHRConstraint constraint; private String factClassName; private TypeDesc factTypeDesc; private ClassBuilder classBuilder; private TypeDesc storeTypeDesc; private TypeDesc[] storeTypeDescArray; private TypeDesc[] parameterTypeDescs; private boolean supportsRemoval; CHRFactCodeGenerator(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRConstraint constraint) { this.storeClassBuilder = storeClassBuilder; this.ruleset = ruleset; this.constraint = constraint; this.moduleBuilder = storeClassBuilder.getModuleBuilder(); this.jtt = moduleBuilder.getJavaTypeTranslator(); this.storeTypeDesc = storeClassBuilder.getType(); this.storeTypeDescArray = new TypeDesc[] { storeTypeDesc }; this.factClassName = storeClassBuilder.getClassName() + "$" + constraint.name; this.factTypeDesc = TypeDesc.forClass(factClassName); this.classBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, factClassName, CHRFact_name); this.parameterTypeDescs = jtt.toTypeDescs(constraint.parameterTypes); this.supportsRemoval = constraint.mayBeRemoved(); } public void generate(ArrayList hashIndexInitializations) { generateFields(hashIndexInitializations); hashIndexInitializations.add(new StoreInitialization(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, constraint.name + "$temp", factTypeDesc, factClassName)); generateIndices(); generateAdd(); if(supportsRemoval) generateRemove(); generateConstructor(); classBuilder.addDefaultConstructor(); moduleBuilder.addClass(classBuilder); } private void generateIndices() { // public ExampleFact ExampleFact$bf(int c0) { // ExampleFact$temp.c0 = c0; // return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp); // } for(IndexInfo indexInfo : constraint.getIndices()) { if(indexInfo.indexMask != 0) { ArrayList getParameterTypeDescs = new ArrayList(constraint.parameterTypes.length); for(int i=0;i>i)&1)==1) getParameterTypeDescs.add(parameterTypeDescs[i]); MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, constraint.name + "$" + indexInfo.indexName, factTypeDesc, getParameterTypeDescs.toArray(new TypeDesc[getParameterTypeDescs.size()])); // ExampleFact$temp.c0 = c0; mb.loadThis(); mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$temp", factTypeDesc); LocalVariable tempFactVar = mb.createLocalVariable("temp", factTypeDesc); mb.storeLocal(tempFactVar); int parameterId=0; for(int i=0;i>i)&1)==1) { TypeDesc typeDesc = parameterTypeDescs[i]; if(!typeDesc.equals(TypeDesc.VOID)) { mb.loadLocal(tempFactVar); mb.loadLocal(mb.getParameter(parameterId)); mb.storeField(factClassName, CHRCodeGenerationConstants.fieldName(i), typeDesc); } ++parameterId; } // return (ExampleFact)ExampleFact_bfIndex.getEqual(ExampleFact$temp); mb.loadThis(); mb.loadField(storeClassBuilder.getClassName(), constraint.name + "$" + indexInfo.indexName, CHRHashIndex); mb.loadLocal(tempFactVar); mb.invokeVirtual(CHRHashIndex_name, supportsRemoval ? "getEqual" : "getEqualNoRemovals", TypeDesc.OBJECT, Constants.OBJECTS[1]); mb.checkCast(factTypeDesc); mb.returnValue(factTypeDesc); mb.finish(); } } } private void generateConstructor() { // public ExampleFact(int id, int c0, int c1) { // this.id = id; // this.c0 = c0; // this.c1 = c1; // } ArrayList constructorParameters = new ArrayList(parameterTypeDescs.length+1); constructorParameters.add(FACT_ID_TYPE); for(TypeDesc typeDesc : parameterTypeDescs) { if(typeDesc.equals(TypeDesc.VOID)) continue; constructorParameters.add(typeDesc); } MethodBuilderBase mb = classBuilder.addConstructorBase(Opcodes.ACC_PUBLIC, constructorParameters.toArray(new TypeDesc[constructorParameters.size()])); mb.loadThis(); mb.invokeConstructor(classBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY); mb.loadThis(); mb.loadLocal(mb.getParameter(0)); mb.storeField(CHRFact_name, "id", FACT_ID_TYPE); for(int i=0,parameterId=1;i hashIndexInitializations) { // public int id; // public int c0; // key // public int c1; // public ExampleFact bfPrev; // public ExampleFact bfNext; //classBuilder.addField(Opcodes.ACC_PUBLIC, "id", FACT_ID_TYPE); for(int i=0;i