]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/SSAModule.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / ssa / SSAModule.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/SSAModule.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/SSAModule.java
new file mode 100644 (file)
index 0000000..9ca2303
--- /dev/null
@@ -0,0 +1,220 @@
+package org.simantics.scl.compiler.internal.codegen.ssa;
+
+import java.util.ArrayList;
+
+import org.cojen.classfile.TypeDesc;
+import org.objectweb.asm.Opcodes;
+import org.simantics.scl.compiler.common.names.Name;
+import org.simantics.scl.compiler.constants.JavaStaticField;
+import org.simantics.scl.compiler.constants.JavaStaticMethod;
+import org.simantics.scl.compiler.constants.SCLConstant;
+import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.errors.ErrorLog;
+import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
+import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
+import org.simantics.scl.compiler.internal.codegen.utils.CodeBuildingException;
+import org.simantics.scl.compiler.internal.codegen.utils.Constants;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
+import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
+import org.simantics.scl.compiler.internal.codegen.utils.NameMangling;
+import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
+import org.simantics.scl.compiler.internal.codegen.utils.SSALambdaLiftingContext;
+import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
+import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
+import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.runtime.tuple.Tuple2;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.procedure.TObjectObjectProcedure;
+import gnu.trove.procedure.TObjectProcedure;
+
+public class SSAModule {
+    THashMap<Name, SCLConstant> functions = new THashMap<Name, SCLConstant>();
+    ArrayList<Tuple2> staticFields = new ArrayList<Tuple2>();
+
+    public void put(Name name, SCLConstant function) {
+        functions.put(name, function);
+    } 
+    
+    public SCLConstant get(Name name) {
+        return functions.get(name);
+    }
+    
+    @Override
+    public String toString() {
+        final StringBuilder b = new StringBuilder();
+        functions.forEachEntry(new TObjectObjectProcedure<Name, SCLConstant>() {            
+            @Override
+            public boolean execute(Name name, SCLConstant function) {   
+                b.append(name.name);
+                b.append(" :: ");
+                b.append(function.getType());
+                b.append('\n');
+                if(function.isPrivate())
+                    b.append("PRIVATE ");
+                b.append(name);
+                b.append(" =\n");
+                PrintingContext context = new PrintingContext();
+                context.indent();
+                function.getDefinition().toString(context);
+                b.append(context.toString());
+                return true;
+            }
+        });
+        return b.toString();
+    }
+    
+    public void validate(SSAValidationContext context) {
+        for(SCLConstant function : functions.values()) {
+            try {            
+                function.getDefinition().validate(context);
+            } catch(RuntimeException e) {
+                System.out.println("-- VALIDATE " + function.getName() + " ----------------");
+                PrintingContext printingContext = new PrintingContext();
+                printingContext.setErrorMarker(context.errorMarker);
+                function.getDefinition().toString(printingContext);
+                System.out.println(printingContext.toString());
+                throw e;
+            }
+        }
+    }
+
+    public void validate() {
+        SSAValidationContext context = new SSAValidationContext();
+        validate(context);
+        //context.checkReferences();
+    }
+
+    public boolean simplify(Environment environment, int phase) {
+        SSASimplificationContext context = new SSASimplificationContext(this, environment, phase);
+        for(SCLConstant function : functions.values().toArray(new SCLConstant[functions.size()]))
+            if(functions.containsKey(function.getName())) {
+                if(function.isPrivate() && function.hasNoOccurences()) {
+                    function.getDefinition().destroy();
+                    functions.remove(function.getName());
+                    context.markModified("SSAModule.dead-function " + function.getName());
+                }
+                else
+                    function.simplify(context);
+            }
+        return context.didModify();
+    }
+
+    public void generateCode(final ModuleBuilder moduleBuilder) throws CodeBuildingException {
+        final String moduleClassName = moduleBuilder.getNamingPolicy().getModuleClassName();
+        if(SCLCompilerConfiguration.TRACE_METHOD_CREATION)
+            System.out.println("Create class " + moduleClassName);
+        final ClassBuilder classFile = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, moduleClassName,
+                "java/lang/Object");        
+        classFile.setSourceFile("_SCL_Module");
+        functions.forEachValue(new TObjectProcedure<SCLConstant>() {
+            @Override
+            public boolean execute(SCLConstant function) {
+                if(function.getBase() == null) {
+                    Name name = function.getName();
+                    SSAFunction definition = function.getDefinition();
+                    String javaName = NameMangling.mangle(name.name);
+                    
+                    if(definition.getArity() == 0) {
+                        // Not a function
+                        TypeDesc typeDesc = moduleBuilder.getJavaTypeTranslator().toTypeDesc(definition.getReturnType());
+                        if(typeDesc != TypeDesc.VOID) {
+                            // Case where typeDesc is VOID is somewhat degenerated
+                            
+                            String initClassName = moduleBuilder.getNamingPolicy().getFreshClosureClassName();
+                            function.setBase(new JavaStaticField(initClassName, "VALUE", definition.getReturnType(), -1));
+                            
+                            ClassBuilder initClass = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, initClassName, "java/lang/Object");
+                            initClass.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "VALUE", typeDesc);
+                            
+                            MethodBuilderBase classInitializer = initClass.addInitializerBase();
+                            classInitializer.invokeStatic(moduleClassName, javaName,
+                                    typeDesc,
+                                    Constants.EMPTY_TYPEDESC_ARRAY);
+                            classInitializer.storeStaticField(initClassName, "VALUE", typeDesc);
+                            classInitializer.returnVoid();
+                            classInitializer.finish();
+                            moduleBuilder.addClass(initClass);
+                            return true;
+                        }
+                    }
+                    
+                    function.setBase(new JavaStaticMethod(
+                            moduleClassName, javaName,
+                            definition.getEffect(),
+                            definition.getTypeParameters(),
+                            definition.getReturnType(), 
+                            definition.getParameterTypes()));
+                }
+                return true;
+            }            
+        });
+        
+        functions.forEachValue(new TObjectProcedure<SCLConstant>() {
+            @Override
+            public boolean execute(SCLConstant function) {     
+                JavaTypeTranslator javaTypeTranslator = moduleBuilder.getJavaTypeTranslator();
+                SSAFunction def = function.getDefinition();
+                MethodBuilder mb = classFile.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, 
+                        NameMangling.mangle(function.getName().name), 
+                        javaTypeTranslator.getTypeDesc(def.getReturnCont()),
+                        JavaTypeTranslator.filterVoid(javaTypeTranslator.getTypeDescs(def.getParameters()))
+                        );
+                def.generateCode(mb);
+                mb.finish();
+                return true;
+            }
+        });
+
+        JavaTypeTranslator javaTypeTranslator = moduleBuilder.getJavaTypeTranslator();
+        for(Tuple2 tuple : staticFields) {
+               classFile.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, (String)tuple.c0, 
+                       javaTypeTranslator.toTypeDesc((Type)tuple.c1));
+        }
+        
+        classFile.addDefaultConstructor();
+        
+        moduleBuilder.addClass(classFile);
+    }
+    
+    /**
+     * Marks those BoundVars that are computed when pushed
+     * to stack and not where they are defined.
+     */
+    public void markGenerateOnFly() {
+        functions.forEachValue(new TObjectProcedure<SCLConstant>() {            
+            @Override
+            public boolean execute(SCLConstant func) {
+                func.getDefinition().markGenerateOnFly();
+                return true;
+            }
+        });        
+    }
+    
+    public void addStaticField(Tuple2 tuple) {
+       staticFields.add(tuple);
+    }
+
+    public SCLConstant remove(Name name) {
+        return functions.remove(name);
+    }
+
+    /**
+     * Converts all nested functions to top level functions.
+     */
+    public void lambdaLift(ErrorLog errorLog) {
+        SSALambdaLiftingContext context = new SSALambdaLiftingContext(this, errorLog);
+        //context.validate();
+        for(SCLConstant function : functions.values().toArray(new SCLConstant[functions.size()])) {
+            context.setParentName(function.getName());
+            function.getDefinition().lambdaLift(context);
+        }
+    }
+
+    public void saveInlinableDefinitions() {
+        for(SCLConstant function : functions.values())
+            function.saveInlinableDefinition();
+    }
+}