--- /dev/null
+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();
+ }
+}