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