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