]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/SSAModule.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / ssa / SSAModule.java
1 package org.simantics.scl.compiler.internal.codegen.ssa;
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.common.names.Name;
8 import org.simantics.scl.compiler.constants.JavaStaticField;
9 import org.simantics.scl.compiler.constants.JavaStaticMethod;
10 import org.simantics.scl.compiler.constants.SCLConstant;
11 import org.simantics.scl.compiler.environment.Environment;
12 import org.simantics.scl.compiler.errors.ErrorLog;
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.CodeBuildingException;
16 import org.simantics.scl.compiler.internal.codegen.utils.Constants;
17 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
18 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
19 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
20 import org.simantics.scl.compiler.internal.codegen.utils.NameMangling;
21 import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
22 import org.simantics.scl.compiler.internal.codegen.utils.SSALambdaLiftingContext;
23 import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
24 import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
25 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 import gnu.trove.map.hash.THashMap;
30 import gnu.trove.procedure.TObjectObjectProcedure;
31 import gnu.trove.procedure.TObjectProcedure;
32
33 public class SSAModule {
34
35     private static final Logger LOGGER = LoggerFactory.getLogger(SSAModule.class);
36
37     THashMap<Name, SCLConstant> functions = new THashMap<Name, SCLConstant>();
38     ArrayList<StaticField> staticFields = new ArrayList<StaticField>();
39     public ArrayList<SSAClosure> closuresToGenerate = new ArrayList<SSAClosure>(); 
40
41     public void put(Name name, SCLConstant function) {
42         functions.put(name, function);
43     } 
44     
45     public SCLConstant get(Name name) {
46         return functions.get(name);
47     }
48     
49     @Override
50     public String toString() {
51         final StringBuilder b = new StringBuilder();
52         functions.forEachEntry(new TObjectObjectProcedure<Name, SCLConstant>() {            
53             @Override
54             public boolean execute(Name name, SCLConstant function) {   
55                 b.append(name.name);
56                 b.append(" :: ");
57                 b.append(function.getType());
58                 b.append('\n');
59                 if(function.isPrivate())
60                     b.append("PRIVATE ");
61                 b.append(name);
62                 b.append(" =\n");
63                 PrintingContext context = new PrintingContext();
64                 context.indent();
65                 function.getDefinition().toString(context);
66                 b.append(context.toString());
67                 return true;
68             }
69         });
70         return b.toString();
71     }
72     
73     public void validate(SSAValidationContext context) {
74         for(SCLConstant function : functions.values()) {
75             try {            
76                 function.getDefinition().validate(context);
77             } catch(RuntimeException e) {
78                 LOGGER.info("-- VALIDATE " + function.getName() + " ----------------");
79                 PrintingContext printingContext = new PrintingContext();
80                 printingContext.setErrorMarker(context.errorMarker);
81                 function.getDefinition().toString(printingContext);
82                 LOGGER.info(printingContext.toString());
83                 throw e;
84             }
85         }
86     }
87
88     public void validate() {
89         SSAValidationContext context = new SSAValidationContext();
90         validate(context);
91         //context.checkReferences();
92     }
93
94     public boolean simplify(Environment environment, int phase) {
95         SSASimplificationContext context = new SSASimplificationContext(this, environment, phase);
96         for(SCLConstant function : functions.values().toArray(new SCLConstant[functions.size()]))
97             if(functions.containsKey(function.getName())) {
98                 if(function.isPrivate() && function.hasNoOccurences()) {
99                     function.getDefinition().destroy();
100                     functions.remove(function.getName());
101                     context.markModified("SSAModule.dead-function " + function.getName());
102                 }
103                 else
104                     function.simplify(context);
105             }
106         return context.didModify();
107     }
108
109     public void generateCode(final ModuleBuilder moduleBuilder) throws CodeBuildingException {
110         final String moduleClassName = moduleBuilder.getNamingPolicy().getModuleClassName();
111         if(SCLCompilerConfiguration.TRACE_METHOD_CREATION)
112             LOGGER.info("Create class " + moduleClassName);
113         final ClassBuilder classFile = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, moduleClassName,
114                 "java/lang/Object");        
115         classFile.setSourceFile(moduleBuilder.getNamingPolicy().getModuleName());
116         functions.forEachValue(new TObjectProcedure<SCLConstant>() {
117             @Override
118             public boolean execute(SCLConstant function) {
119                 if(function.getBase() == null) {
120                     Name name = function.getName();
121                     SSAFunction definition = function.getDefinition();
122                     String javaName = NameMangling.mangle(name.name);
123                     
124                     if(definition.getArity() == 0) {
125                         // Not a function
126                         TypeDesc typeDesc = moduleBuilder.getJavaTypeTranslator().toTypeDesc(definition.getReturnType());
127                         if(typeDesc != TypeDesc.VOID) {
128                             // Case where typeDesc is VOID is somewhat degenerated
129                             
130                             String initClassName = moduleBuilder.getNamingPolicy().getFreshClosureClassName();
131                             function.setBase(new JavaStaticField(initClassName, "VALUE", definition.getReturnType(), -1));
132                             
133                             ClassBuilder initClass = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, initClassName, "java/lang/Object");
134                             initClass.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "VALUE", typeDesc);
135                             
136                             MethodBuilderBase classInitializer = initClass.addInitializerBase();
137                             classInitializer.invokeStatic(moduleClassName, javaName,
138                                     typeDesc,
139                                     Constants.EMPTY_TYPEDESC_ARRAY);
140                             classInitializer.storeStaticField(initClassName, "VALUE", typeDesc);
141                             classInitializer.returnVoid();
142                             classInitializer.finish();
143                             moduleBuilder.addClass(initClass);
144                             return true;
145                         }
146                     }
147                     
148                     function.setBase(new JavaStaticMethod(
149                             moduleClassName, javaName,
150                             definition.getEffect(),
151                             definition.getTypeParameters(),
152                             definition.getReturnType(), 
153                             definition.getParameterTypes()));
154                 }
155                 return true;
156             }            
157         });
158         
159         functions.forEachValue(new TObjectProcedure<SCLConstant>() {
160             @Override
161             public boolean execute(SCLConstant function) {     
162                 JavaTypeTranslator javaTypeTranslator = moduleBuilder.getJavaTypeTranslator();
163                 SSAFunction def = function.getDefinition();
164                 MethodBuilder mb = classFile.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, 
165                         NameMangling.mangle(function.getName().name), 
166                         javaTypeTranslator.getTypeDesc(def.getReturnCont()),
167                         JavaTypeTranslator.filterVoid(javaTypeTranslator.getTypeDescs(def.getParameters()))
168                         );
169                 def.generateCode(mb);
170                 mb.finish();
171                 return true;
172             }
173         });
174
175         JavaTypeTranslator javaTypeTranslator = moduleBuilder.getJavaTypeTranslator();
176         for(StaticField tuple : staticFields) {
177                 classFile.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, tuple.name, 
178                         javaTypeTranslator.toTypeDesc(tuple.type));
179         }
180         
181         classFile.addDefaultConstructor();
182         
183         moduleBuilder.addClass(classFile);
184         
185         for(SSAClosure closure : closuresToGenerate)
186             closure.generateCode(moduleBuilder);
187     }
188     
189     /**
190      * Marks those BoundVars that are computed when pushed
191      * to stack and not where they are defined.
192      */
193     public void markGenerateOnFly() {
194         functions.forEachValue(new TObjectProcedure<SCLConstant>() {            
195             @Override
196             public boolean execute(SCLConstant func) {
197                 func.getDefinition().markGenerateOnFly();
198                 return true;
199             }
200         });        
201     }
202     
203     public void addStaticField(StaticField tuple) {
204         staticFields.add(tuple);
205     }
206
207     public SCLConstant remove(Name name) {
208         return functions.remove(name);
209     }
210
211     /**
212      * Converts all nested functions to top level functions.
213      */
214     public void lambdaLift(ErrorLog errorLog) {
215         SSALambdaLiftingContext context = new SSALambdaLiftingContext(this, errorLog);
216         //context.validate();
217         for(SCLConstant function : functions.values().toArray(new SCLConstant[functions.size()])) {
218             context.setParentName(function.getName());
219             function.getDefinition().lambdaLift(context);
220         }
221     }
222
223     public void saveInlinableDefinitions() {
224         for(SCLConstant function : functions.values())
225             function.saveInlinableDefinition();
226     }
227
228     public void cleanup() {
229         for(SSAClosure closure : closuresToGenerate)
230             closure.cleanup();
231         for(SCLConstant constant : functions.values())
232             constant.cleanup();
233     }
234 }