]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/chr/CHRRuntimeRulesetCodeGenerator.java
9ff56eda4cc45eb27dcf29b00c0f9789816215c8
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / chr / CHRRuntimeRulesetCodeGenerator.java
1 package org.simantics.scl.compiler.internal.codegen.chr;
2
3 import java.util.ArrayList;
4
5 import org.cojen.classfile.TypeDesc;
6 import org.objectweb.asm.Opcodes;
7 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
8 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
9 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
10 import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement;
11 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
12 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
13 import org.simantics.scl.compiler.internal.codegen.utils.Constants;
14 import org.simantics.scl.compiler.internal.codegen.utils.LocalVariable;
15 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
16 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
17 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
18
19 public class CHRRuntimeRulesetCodeGenerator implements CHRCodeGenerationConstants {
20
21     public static void generateRuntimeRuleset(ModuleBuilder moduleBuilder, CHRRuleset ruleset) {
22         ClassBuilder storeClassBuilder = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, ruleset.runtimeRulesetClassName, CHRRuntimeRuleset_name);
23         if(ruleset.rulesetObject.parameters == null)
24             ruleset.rulesetObject.parameters = new BoundVar[0];
25         TypeDesc[] parameterTypeDescs = ruleset.rulesetObject.parameterTypeDescs = moduleBuilder.getJavaTypeTranslator().getTypeDescs(ruleset.rulesetObject.parameters); 
26
27         ArrayList<StoreInitialization> hashIndexInitializations = new ArrayList<StoreInitialization>();
28         for(CHRConstraint constraint : ruleset.constraints)
29             generateFact(storeClassBuilder, ruleset, constraint, hashIndexInitializations);
30         
31         for(int i=ruleset.rules.size()-1;i>=0;--i)
32             generateFactContainer(storeClassBuilder, ruleset, ruleset.rules.get(i));
33
34         // Fields
35         for(int i=0;i<parameterTypeDescs.length;++i) {
36             TypeDesc typeDesc = parameterTypeDescs[i];
37             if(typeDesc.equals(TypeDesc.VOID))
38                 continue;
39             storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, CHRCodeGenerationConstants.parameterName(i), typeDesc);
40         }
41         for(StoreInitialization ini : hashIndexInitializations)
42             storeClassBuilder.addField(ini.access, ini.fieldName, ini.fieldType);
43         for(CHRRule rule : ruleset.rules)
44             storeClassBuilder.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, CHRCodeGenerationConstants.priorityName(rule.priority), CHRPriorityFactContainer);
45         if(ruleset.extensible)
46             for(CHRConstraint constraint : ruleset.constraints)
47                 if(constraint.nextContainerFieldName != null)
48                     storeClassBuilder.addField(Opcodes.ACC_PUBLIC, constraint.nextContainerFieldName, CHRPriorityFactContainer);
49         if(ruleset.extensible)
50             storeClassBuilder.addField(Opcodes.ACC_PUBLIC, "currentId", FACT_ID_TYPE);
51         
52         // Constructors
53
54         {
55             MethodBuilder mb = storeClassBuilder.addConstructor(Opcodes.ACC_PUBLIC, parameterTypeDescs);
56                     //TypeDesc.concat(ruleset.parameterTypeDescs, includeTypeDescs));
57             mb.loadThis();
58             mb.invokeConstructor(storeClassBuilder.getSuperClassName(), Constants.EMPTY_TYPEDESC_ARRAY);
59             int p=0;
60             for(int i=0;i<parameterTypeDescs.length;++i) {
61                 TypeDesc typeDesc = parameterTypeDescs[i];
62                 if(typeDesc.equals(TypeDesc.VOID))
63                     continue;
64                 mb.loadThis();
65                 mb.loadLocal(mb.getParameter(p++));
66                 mb.storeField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]);
67             }
68             for(StoreInitialization ini : hashIndexInitializations) {
69                 mb.loadThis();
70                 mb.newObject(ini.className);
71                 mb.dup();
72                 mb.invokeConstructor(ini.className, Constants.EMPTY_TYPEDESC_ARRAY);
73                 mb.storeField(ruleset.runtimeRulesetClassName, ini.fieldName, ini.fieldType);
74             }
75             TypeDesc[] runtimeRulesetTypeDescArray = new TypeDesc[] {TypeDesc.forClass(storeClassBuilder.getClassName())};
76             for(CHRRule rule : ruleset.rules) {
77                 mb.loadThis();
78                 mb.newObject(rule.containerClassName);
79                 mb.dup();
80                 mb.loadThis();
81                 mb.invokeConstructor(rule.containerClassName, runtimeRulesetTypeDescArray);
82                 mb.storeField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.priorityName(rule.priority), CHRPriorityFactContainer);
83             }
84             mb.returnVoid();
85             mb.finish();
86         }
87         
88         // Registration
89         
90         for(IncludeStatement include : ruleset.includes) {
91             {
92                 MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "register", TypeDesc.VOID,
93                         new TypeDesc[] {CHRContext, include.ruleset.runtimeRulesetTypeDesc});
94                 LocalVariable contextVar = mb.getParameter(0);
95                 LocalVariable importedStore = mb.getParameter(1);
96                 ArrayList<CHRConstraint> list = ruleset.inverseActiveConstraintSourceMap.get(include);
97                 if(list != null)
98                     for(CHRConstraint constraint : list) {
99                         int minimumPriority = ruleset.getMinimumPriority(constraint);
100                         if(minimumPriority == Integer.MAX_VALUE)
101                             continue;
102                         mb.loadLocal(importedStore);
103                         mb.loadThis();
104                         mb.loadField(storeClassBuilder.getClassName(), CHRCodeGenerationConstants.priorityName(minimumPriority), CHRPriorityFactContainer);
105                         mb.storeField(include.ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.nextContainerName(constraint.name), CHRPriorityFactContainer);
106                     }
107                 
108                 // update context id
109                 mb.loadLocal(contextVar);
110                 mb.loadLocal(contextVar);
111                 mb.loadField(CHRContext_name, "currentId", FACT_ID_TYPE);
112                 mb.loadLocal(importedStore);
113                 mb.loadField(include.ruleset.runtimeRulesetClassName, "currentId", FACT_ID_TYPE);
114                 mb.invokeStatic("java/lang/Math", "max", FACT_ID_TYPE, new TypeDesc[] {FACT_ID_TYPE, FACT_ID_TYPE});
115                 mb.storeField(CHRContext_name, "currentId", FACT_ID_TYPE);
116                 
117                 mb.returnVoid();
118                 mb.finish();
119             }
120             
121             {
122                 MethodBuilderBase mb = storeClassBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "unregister", TypeDesc.VOID,
123                         new TypeDesc[] {CHRContext, include.ruleset.runtimeRulesetTypeDesc});
124                 LocalVariable contextVar = mb.getParameter(0);
125                 LocalVariable importedStore = mb.getParameter(1);
126                 ArrayList<CHRConstraint> list = ruleset.inverseActiveConstraintSourceMap.get(include);
127                 if(list != null)
128                     for(CHRConstraint constraint : list) {
129                         int minimumPriority = ruleset.getMinimumPriority(constraint);
130                         if(minimumPriority == Integer.MAX_VALUE)
131                             continue;
132                         mb.loadLocal(importedStore);
133                         mb.loadNull();
134                         mb.storeField(include.ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.nextContainerName(constraint.name), CHRPriorityFactContainer);
135                     }
136                 
137                 // store context id
138                 mb.loadLocal(importedStore);
139                 mb.loadLocal(contextVar);
140                 mb.loadField(CHRContext_name, "currentId", FACT_ID_TYPE);
141                 mb.storeField(include.ruleset.runtimeRulesetClassName, "currentId", FACT_ID_TYPE);
142                 
143                 mb.returnVoid();
144                 mb.finish();
145             }
146         }
147         
148         if(ruleset.initializer != null) {
149             MethodBuilder mb = storeClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "initialize", TypeDesc.VOID, new TypeDesc[] {CHRContext});
150             ruleset.rulesetObject.realizeMethod(mb,
151                     (i, target) -> {
152                         mb.loadThis();
153                         mb.loadField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]);
154                         mb.store(target);
155                     },
156                     ruleset.initializer, mb.getThis(ruleset.runtimeRulesetTypeDesc), mb.getParameter(0));
157             mb.finish();
158         }
159         if(ruleset.deinitializer != null) {
160             MethodBuilder mb = storeClassBuilder.addMethod(Opcodes.ACC_PUBLIC, "deinitialize", TypeDesc.VOID, new TypeDesc[] {CHRContext});
161             ruleset.rulesetObject.realizeMethod(mb,
162                     (i, target) -> {
163                         mb.loadThis();
164                         mb.loadField(ruleset.runtimeRulesetClassName, CHRCodeGenerationConstants.parameterName(i), parameterTypeDescs[i]);
165                         mb.store(target);
166                     },
167                     ruleset.deinitializer, mb.getThis(ruleset.runtimeRulesetTypeDesc), mb.getParameter(0));
168             mb.finish();
169         }
170
171         moduleBuilder.addClass(storeClassBuilder);
172     }
173
174     private static void generateFact(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRConstraint constraint, ArrayList<StoreInitialization> hashIndexInitializations) {
175         CHRFactCodeGenerator generator = new CHRFactCodeGenerator(storeClassBuilder, ruleset, constraint);
176         generator.generate(hashIndexInitializations);
177     }
178
179     private static void generateFactContainer(ClassBuilder storeClassBuilder, CHRRuleset ruleset, CHRRule rule) {
180         CHRPriorityFactContainerCodeGenerator generator = new CHRPriorityFactContainerCodeGenerator(storeClassBuilder, ruleset, rule); 
181         generator.generate();
182         rule.containerClassName = generator.containerClassName;
183     }
184 }