1 package org.simantics.scl.compiler.internal.codegen.ssa;
3 import java.util.ArrayList;
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;
29 import gnu.trove.map.hash.THashMap;
30 import gnu.trove.procedure.TObjectObjectProcedure;
31 import gnu.trove.procedure.TObjectProcedure;
33 public class SSAModule {
35 private static final Logger LOGGER = LoggerFactory.getLogger(SSAModule.class);
37 THashMap<Name, SCLConstant> functions = new THashMap<Name, SCLConstant>();
38 ArrayList<StaticField> staticFields = new ArrayList<StaticField>();
39 public ArrayList<SSAClosure> closuresToGenerate = new ArrayList<SSAClosure>();
41 public void put(Name name, SCLConstant function) {
42 functions.put(name, function);
45 public SCLConstant get(Name name) {
46 return functions.get(name);
50 public String toString() {
51 final StringBuilder b = new StringBuilder();
52 functions.forEachEntry(new TObjectObjectProcedure<Name, SCLConstant>() {
54 public boolean execute(Name name, SCLConstant function) {
57 b.append(function.getType());
59 if(function.isPrivate())
63 PrintingContext context = new PrintingContext();
65 function.getDefinition().toString(context);
66 b.append(context.toString());
73 public void validate(SSAValidationContext context) {
74 for(SCLConstant function : functions.values()) {
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());
88 public void validate() {
89 SSAValidationContext context = new SSAValidationContext();
91 //context.checkReferences();
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());
104 function.simplify(context);
106 return context.didModify();
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,
115 classFile.setSourceFile(moduleBuilder.getNamingPolicy().getModuleName());
116 functions.forEachValue(new TObjectProcedure<SCLConstant>() {
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);
124 if(definition.getArity() == 0) {
126 TypeDesc typeDesc = moduleBuilder.getJavaTypeTranslator().toTypeDesc(definition.getReturnType());
127 if(typeDesc != TypeDesc.VOID) {
128 // Case where typeDesc is VOID is somewhat degenerated
130 String initClassName = moduleBuilder.getNamingPolicy().getFreshClosureClassName();
131 function.setBase(new JavaStaticField(initClassName, "VALUE", definition.getReturnType(), -1));
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);
136 MethodBuilderBase classInitializer = initClass.addInitializerBase();
137 classInitializer.invokeStatic(moduleClassName, javaName,
139 Constants.EMPTY_TYPEDESC_ARRAY);
140 classInitializer.storeStaticField(initClassName, "VALUE", typeDesc);
141 classInitializer.returnVoid();
142 classInitializer.finish();
143 moduleBuilder.addClass(initClass);
148 function.setBase(new JavaStaticMethod(
149 moduleClassName, javaName,
150 definition.getEffect(),
151 definition.getTypeParameters(),
152 definition.getReturnType(),
153 definition.getParameterTypes()));
159 functions.forEachValue(new TObjectProcedure<SCLConstant>() {
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()))
169 def.generateCode(mb);
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));
181 classFile.addDefaultConstructor();
183 moduleBuilder.addClass(classFile);
185 for(SSAClosure closure : closuresToGenerate)
186 closure.generateCode(moduleBuilder);
190 * Marks those BoundVars that are computed when pushed
191 * to stack and not where they are defined.
193 public void markGenerateOnFly() {
194 functions.forEachValue(new TObjectProcedure<SCLConstant>() {
196 public boolean execute(SCLConstant func) {
197 func.getDefinition().markGenerateOnFly();
203 public void addStaticField(StaticField tuple) {
204 staticFields.add(tuple);
207 public SCLConstant remove(Name name) {
208 return functions.remove(name);
212 * Converts all nested functions to top level functions.
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);
223 public void saveInlinableDefinitions() {
224 for(SCLConstant function : functions.values())
225 function.saveInlinableDefinition();
228 public void cleanup() {
229 for(SSAClosure closure : closuresToGenerate)
231 for(SCLConstant constant : functions.values())