X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Fcompilation%2FCodeGeneration.java;fp=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Fcompilation%2FCodeGeneration.java;h=470b8e9f0701c0418fb08bf02757e0b4717616d5;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/CodeGeneration.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/CodeGeneration.java new file mode 100644 index 000000000..470b8e9f0 --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/CodeGeneration.java @@ -0,0 +1,432 @@ +package org.simantics.scl.compiler.compilation; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +import org.cojen.classfile.TypeDesc; +import org.objectweb.asm.Opcodes; +import org.simantics.scl.compiler.common.datatypes.Constructor; +import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; +import org.simantics.scl.compiler.common.names.Name; +import org.simantics.scl.compiler.constants.LocalFieldConstant; +import org.simantics.scl.compiler.constants.LocalVariableConstant; +import org.simantics.scl.compiler.constants.NoRepConstant; +import org.simantics.scl.compiler.constants.SCLConstant; +import org.simantics.scl.compiler.constants.ThisConstant; +import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; +import org.simantics.scl.compiler.elaboration.expressions.Expression; +import org.simantics.scl.compiler.elaboration.macros.StandardMacroRule; +import org.simantics.scl.compiler.elaboration.modules.InlineProperty; +import org.simantics.scl.compiler.elaboration.modules.MethodImplementation; +import org.simantics.scl.compiler.elaboration.modules.PrivateProperty; +import org.simantics.scl.compiler.elaboration.modules.SCLValue; +import org.simantics.scl.compiler.elaboration.modules.SCLValueProperty; +import org.simantics.scl.compiler.elaboration.modules.TypeClass; +import org.simantics.scl.compiler.elaboration.modules.TypeClassInstance; +import org.simantics.scl.compiler.elaboration.modules.TypeClassMethod; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.errors.ErrorLog; +import org.simantics.scl.compiler.internal.codegen.references.IVal; +import org.simantics.scl.compiler.internal.codegen.references.Val; +import org.simantics.scl.compiler.internal.codegen.ssa.SSAModule; +import org.simantics.scl.compiler.internal.codegen.types.JavaReferenceValidator; +import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator; +import org.simantics.scl.compiler.internal.codegen.types.StandardTypeConstructor; +import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder; +import org.simantics.scl.compiler.internal.codegen.utils.CodeBuilderUtils; +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.JavaNamingPolicy; +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.writer.CodeWriter; +import org.simantics.scl.compiler.internal.codegen.writer.ExternalConstant; +import org.simantics.scl.compiler.internal.codegen.writer.ModuleWriter; +import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression; +import org.simantics.scl.compiler.module.ConcreteModule; +import org.simantics.scl.compiler.top.SCLCompilerConfiguration; +import org.simantics.scl.compiler.types.TCon; +import org.simantics.scl.compiler.types.TPred; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.exceptions.MatchException; +import org.simantics.scl.compiler.types.util.MultiFunction; + +import gnu.trove.procedure.TObjectObjectProcedure; +import gnu.trove.procedure.TObjectProcedure; + +public class CodeGeneration { + + public static final int OPTIMIZATION_PHASES = 2; + + ErrorLog errorLog; + Environment environment; + JavaNamingPolicy namingPolicy; + JavaTypeTranslator javaTypeTranslator; + JavaReferenceValidator validator; + ConcreteModule module; + ModuleBuilder moduleBuilder; + + // creates + SSAModule ssaModule; + ExternalConstant[] externalConstants; + Map classes; + + @SuppressWarnings("unchecked") + public CodeGeneration(ErrorLog errorLog, + Environment environment, + JavaNamingPolicy namingPolicy, JavaTypeTranslator javaTypeTranslator, + JavaReferenceValidator javaReferenceValidator, + ConcreteModule module) { + this.errorLog = errorLog; + this.environment = environment; + this.namingPolicy = namingPolicy; + this.javaTypeTranslator = javaTypeTranslator; + this.module = module; + this.validator = (JavaReferenceValidator) javaReferenceValidator; + + moduleBuilder = new ModuleBuilder(namingPolicy, javaTypeTranslator); + } + + public void simplifyValues() { + //System.out.println("===== Simplify values ====="); + + Collection values = module.getValues(); + SimplificationContext simplificationContext = + new SimplificationContext(environment, errorLog, + javaTypeTranslator, validator); + //System.out.println("-----------------------------------------------"); + SCLValue[] valueArray = values.toArray(new SCLValue[values.size()]); + + for(SCLValue value : valueArray) { + if(value.getMacroRule() instanceof StandardMacroRule) { + StandardMacroRule rule = (StandardMacroRule)value.getMacroRule(); + rule.setBaseExpression(value.getExpression().copy()); + } + } + + // Simplify + for(SCLValue value : valueArray) { + //System.out.println("BEFORE " + value.getName() + " = " + value.getExpression()); + value.getSimplifiedExpression(simplificationContext); + //System.out.println("AFTER " + value.getName() + " = " + value.getExpression()); + } + } + + public void convertToSSA() { + ModuleWriter mw = new ModuleWriter(namingPolicy.getModuleClassName()); + for(SCLValue value : module.getValues()) { + //System.out.println(value.getName().name + " :: " + value.getType()); + Expression expression = value.getExpression(); + if(expression == null) + continue; + + Name name = value.getName(); + DecomposedExpression decomposed = + DecomposedExpression.decompose(expression); + + SCLConstant constant = new SCLConstant(name, value.getType()); + value.setValue(constant); + /*constant.setBase(new JavaStaticMethod( + namingPolicy.getModuleClassName(), namingPolicy.getMethodName(name.name), + decomposed.effect, + decomposed.typeParameters, + decomposed.returnType, + decomposed.parameterTypes));*/ + for(SCLValueProperty prop : value.getProperties()) { + if(prop instanceof InlineProperty) { + InlineProperty inlineProperty = (InlineProperty)prop; + constant.setInlineArity(inlineProperty.arity, inlineProperty.phaseMask); + } + else if(prop == PrivateProperty.INSTANCE) + constant.setPrivate(true); + } + } + // This is quite hackish optimization that can be possibly removed when + // better optimizations exist + /*for(SCLValue value : module.getValues()) { + Expression expression = value.getExpression(); + if(!(expression instanceof EConstant)) + continue; + EConstant constant = (EConstant)expression; + if(constant.getTypeParameters().length > 0) + continue; + + //System.out.println(value.getName() + " <- " + constant.getValue().getName()); + value.setValue(constant.getValue().getValue()); + value.setExpression(null); // HMM?? + }*/ + for(SCLValue value : module.getValues()) { + try { + Expression expression = value.getExpression(); + if(expression == null) + continue; + + DecomposedExpression decomposed = + DecomposedExpression.decompose(expression); + + CodeWriter w = mw.createFunction((SCLConstant)value.getValue(), + decomposed.typeParameters, + decomposed.effect, + decomposed.returnType, + decomposed.parameterTypes); + if(value.getValue() instanceof SCLConstant) // FIXME should be redundant test, if expression is nulled above + ((SCLConstant)value.getValue()).setDefinition(w.getFunction()); + IVal[] parameterVals = w.getParameters(); + for(int i=0;i dataTypes) { + for(StandardTypeConstructor dataType : dataTypes) { + if(dataType.external) + continue; + if(dataType.constructors.length == 1) { + Constructor constructor = dataType.constructors[0]; + if(constructor.parameterTypes.length != 1) { + String javaName = MethodBuilderBase.getClassName(dataType.getTypeDesc()); + if(SCLCompilerConfiguration.TRACE_METHOD_CREATION) + System.out.println("Create class " + javaName); + ClassBuilder cf = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, javaName, "java/lang/Object"); + cf.setSourceFile("_SCL_DataType"); + CodeBuilderUtils.makeRecord(cf, constructor.name.name, + Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, "c", + javaTypeTranslator.toTypeDescs(constructor.parameterTypes), + true); + moduleBuilder.addClass(cf); + } + } + else { + String javaName = MethodBuilderBase.getClassName(dataType.getTypeDesc()); + // Create supertype + { + if(SCLCompilerConfiguration.TRACE_METHOD_CREATION) + System.out.println("Create class " + javaName); + ClassBuilder cf = new ClassBuilder(moduleBuilder, + Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC, + javaName, "java/lang/Object"); + cf.setSourceFile("_SCL_DataType"); + cf.addDefaultConstructor(); + moduleBuilder.addClass(cf); + } + + // Create constructors + for(Constructor constructor : dataType.constructors) { + if(SCLCompilerConfiguration.TRACE_METHOD_CREATION) + System.out.println("Create class " + constructor.javaName); + ClassBuilder cf = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, constructor.javaName, javaName); + cf.setSourceFile("_SCL_DataType"); + CodeBuilderUtils.makeRecord(cf, constructor.name.name, + Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, "c", + javaTypeTranslator.toTypeDescs(constructor.parameterTypes), + true); + moduleBuilder.addClass(cf); + } + } + } + } + + public void generateTypeClasses() { + for(TypeClass typeClass : module.getTypeClasses()) { + final JavaTypeTranslator javaTypeTranslator = moduleBuilder.getJavaTypeTranslator(); + + if(SCLCompilerConfiguration.TRACE_METHOD_CREATION) + System.out.println("Create class " + typeClass.javaName); + final ClassBuilder cf = new ClassBuilder(moduleBuilder, + Opcodes.ACC_INTERFACE | Opcodes.ACC_PUBLIC, + typeClass.javaName, "java/lang/Object"); + + for(int i=0;i() { + @Override + public boolean execute(TypeClassMethod method) { + MultiFunction mfun; + try { + mfun = Types.matchFunction(method.getBaseType(), method.getArity()); + } catch (MatchException e) { + throw new InternalCompilerError("Method " + method.getName() + " has too high arity."); + } + cf.addAbstractMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT, method.getJavaName(), + javaTypeTranslator.toTypeDesc(mfun.returnType), + JavaTypeTranslator.filterVoid(javaTypeTranslator.toTypeDescs(mfun.parameterTypes))); + return true; + } + }); + + moduleBuilder.addClass(cf); + } + } + + public void generateTypeClassInstances() { + module.getTypeInstances().forEachEntry(new TObjectObjectProcedure>() { + + @Override + public boolean execute(TCon typeClass, ArrayList instances) { + for(TypeClassInstance instance : instances) + generateTypeClassInstance(instance); + return true; + } + }); + } + + private void generateTypeClassInstance(final TypeClassInstance instance) { + final JavaTypeTranslator javaTypeTranslator = moduleBuilder.getJavaTypeTranslator(); + + if(SCLCompilerConfiguration.TRACE_METHOD_CREATION) + System.out.println("Create class " + instance.javaName); + final ClassBuilder cb = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, instance.javaName, "java/lang/Object", + instance.typeClass.javaName); + cb.setSourceFile("_SCL_TypeClassInstance"); + + CodeBuilderUtils.makeRecord(cb, instance.javaName, Opcodes.ACC_PRIVATE, "cx", + javaTypeTranslator.toTypeDescs(instance.context), false); + + for(int i=0;i() { + @Override + public boolean execute(TypeClassMethod method) { + MultiFunction mfun; + Type baseType = method.getBaseType(); + try { + mfun = Types.matchFunction(baseType, method.getArity()); + } catch (MatchException e) { + throw new InternalCompilerError("Method " + method.getName() + " has too high arity."); + } + //System.out.println("Interface types: " + Arrays.toString(types)); + TypeDesc[] parameterTypeDescs = javaTypeTranslator.toTypeDescs(mfun.parameterTypes); + TypeDesc returnTypeDesc = javaTypeTranslator.toTypeDesc(mfun.returnType); + MethodBuilder mb = cb.addMethod(Opcodes.ACC_PUBLIC, method.getJavaName(), + returnTypeDesc, + JavaTypeTranslator.filterVoid(parameterTypeDescs)); + + MethodImplementation implementation = + instance.methodImplementations.get(method.getName()); + if(implementation.isDefault) { + IVal function = environment.getValue(implementation.name).getValue(); + + Val[] parameters = new Val[method.getArity() + 1]; + MultiFunction mfun2; + try { + mfun2 = Types.matchFunction(Types.removeForAll(function.getType()), parameters.length); + } catch (MatchException e) { + throw new InternalCompilerError(e); + } + parameters[0] = new ThisConstant(instance.instance); + for(int i=0,j=0;i