package org.simantics.scl.compiler.internal.codegen.chr; import java.util.ArrayList; import org.cojen.classfile.TypeDesc; import org.objectweb.asm.Opcodes; import org.simantics.scl.compiler.elaboration.chr.CHRRule; import org.simantics.scl.compiler.elaboration.chr.CHRRuleset; import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint; import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement; import org.simantics.scl.compiler.internal.codegen.references.BoundVar; 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.MethodBuilder; import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase; import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder; public class CHRRuntimeRulesetCodeGenerator implements CHRCodeGenerationConstants { public static void generateRuntimeRuleset(ModuleBuilder moduleBuilder, CHRRuleset ruleset) { ClassBuilder storeClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, ruleset.runtimeRulesetClassName, CHRRuntimeRuleset_name); if(ruleset.rulesetObject.parameters == null) ruleset.rulesetObject.parameters = new BoundVar[0]; TypeDesc[] parameterTypeDescs = ruleset.rulesetObject.parameterTypeDescs = moduleBuilder.getJavaTypeTranslator().getTypeDescs(ruleset.rulesetObject.parameters); ArrayList hashIndexInitializations = new ArrayList(); for(CHRConstraint constraint : ruleset.constraints) generateFact(storeClassBuilder, ruleset, constraint, hashIndexInitializations); for(int i=ruleset.rules.size()-1;i>=0;--i) generateFactContainer(storeClassBuilder, ruleset, ruleset.rules.get(i)); // Fields for(int i=0;i list = ruleset.inverseActiveConstraintSourceMap.get(include); if(list != null) for(CHRConstraint constraint : list) { int minimumPriority = ruleset.getMinimumPriority(constraint); if(minimumPriority == Integer.MAX_VALUE) continue; mb.loadLocal(importedStore); mb.loadThis(); mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.priorityName(minimumPriority), CHRPriorityFactContainer); mb.storeField(include.ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.nextContainerName(constraint.name), CHRPriorityFactContainer); } // update context id mb.loadLocal(contextVar); mb.loadLocal(contextVar); mb.loadField(CHRContext_name, "currentId", FACT_ID_TYPE); mb.loadLocal(importedStore); mb.loadField(include.ruleset.runtimeRulesetClassName, "currentId", FACT_ID_TYPE); mb.invokeStatic("java/lang/Math", "max", FACT_ID_TYPE, new TypeDesc[] {FACT_ID_TYPE, FACT_ID_TYPE}); mb.storeField(CHRContext_name, "currentId", FACT_ID_TYPE); mb.returnVoid(); mb.finish(); } { MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "unregister", TypeDesc.VOID, new TypeDesc[] {CHRContext, include.ruleset.runtimeRulesetTypeDesc}); LocalVariable contextVar = mb.getParameter(0); LocalVariable importedStore = mb.getParameter(1); ArrayList list = ruleset.inverseActiveConstraintSourceMap.get(include); if(list != null) for(CHRConstraint constraint : list) { int minimumPriority = ruleset.getMinimumPriority(constraint); if(minimumPriority == Integer.MAX_VALUE) continue; mb.loadLocal(importedStore); mb.loadNull(); mb.storeField(include.ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.nextContainerName(constraint.name), CHRPriorityFactContainer); } // store context id mb.loadLocal(importedStore); mb.loadLocal(contextVar); mb.loadField(CHRContext_name, "currentId", FACT_ID_TYPE); mb.storeField(include.ruleset.runtimeRulesetClassName, "currentId", FACT_ID_TYPE); mb.returnVoid(); mb.finish(); } } if(ruleset.initializer != null) { MethodBuilder mb = storeClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "initialize", TypeDesc.VOID, new TypeDesc[] {CHRContext}); ruleset.rulesetObject.realizeMethod(mb, (i, target) -> { mb.loadThis(); mb.loadField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]); mb.store(target); }, ruleset.initializer, mb.getThis(ruleset.runtimeRulesetTypeDesc), mb.getParameter(0)); mb.finish(); } if(ruleset.deinitializer != null) { MethodBuilder mb = storeClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "deinitialize", TypeDesc.VOID, new TypeDesc[] {CHRContext}); ruleset.rulesetObject.realizeMethod(mb, (i, target) -> { mb.loadThis(); mb.loadField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]); mb.store(target); }, ruleset.deinitializer, mb.getThis(ruleset.runtimeRulesetTypeDesc), mb.getParameter(0)); mb.finish(); } moduleBuilder.addClass(storeClassBuilder); } private static void generateFact(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRConstraint constraint, ArrayList hashIndexInitializations) { CHRFactCodeGenerator generator = new CHRFactCodeGenerator(storeClassBuilder, ruleset, constraint); generator.generate(hashIndexInitializations); } private static void generateFactContainer(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRRule rule) { CHRPriorityFactContainerCodeGenerator generator = new CHRPriorityFactContainerCodeGenerator(storeClassBuilder, ruleset, rule); generator.generate(); rule.containerClassName = generator.containerClassName; } }