1 package org.simantics.scl.compiler.constants;
3 import java.util.Arrays;
5 import org.cojen.classfile.TypeDesc;
6 import org.objectweb.asm.Opcodes;
7 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
8 import org.simantics.scl.compiler.internal.codegen.references.Val;
9 import org.simantics.scl.compiler.internal.codegen.types.BTypes;
10 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
11 import org.simantics.scl.compiler.internal.codegen.utils.CodeBuilderUtils;
12 import org.simantics.scl.compiler.internal.codegen.utils.Constants;
13 import org.simantics.scl.compiler.internal.codegen.utils.JavaNamingPolicy;
14 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
15 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
16 import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder;
17 import org.simantics.scl.compiler.internal.codegen.utils.TransientClassBuilder;
18 import org.simantics.scl.compiler.runtime.MutableClassLoader;
19 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
20 import org.simantics.scl.compiler.types.TVar;
21 import org.simantics.scl.compiler.types.Type;
22 import org.simantics.scl.compiler.types.Types;
23 import org.simantics.scl.compiler.types.exceptions.MatchException;
25 import gnu.trove.map.hash.THashMap;
27 public abstract class FunctionValue extends Constant {
29 TVar[] typeParameters;
31 protected Type[] parameterTypes;
34 public FunctionValue(TVar[] typeParameters, Type effect, Type returnType, Type ... parameterTypes) {
35 super(Types.forAll(typeParameters,
36 Types.functionE(parameterTypes, effect, returnType)));
37 this.typeParameters = typeParameters;
38 this.returnType = returnType;
39 this.parameterTypes = parameterTypes;
43 public Type getReturnType() {
47 public Type[] getParameterTypes() {
48 return parameterTypes;
51 public TVar[] getTypeParameters() {
52 return typeParameters;
56 public int getArity() {
57 return parameterTypes.length;
61 public void push(MethodBuilder mb) {
62 apply(mb, Type.EMPTY_ARRAY);
66 public Type apply(MethodBuilder mb, Type[] typeParameters, Val... parameters) {
67 int arity = getArity();
69 /*System.out.println("MONADIC APPLICATION " + this);
70 System.out.println(" call arity: " + parameters.length);
71 System.out.println(" func arity: " + arity);
72 System.out.println(" func monadic: " + isMonadic());
74 if(parameters.length < arity) {
75 ModuleBuilder moduleBuilder = mb.getModuleBuilder();
76 TypeDesc closureClass = moduleBuilder.getClosure(this, parameters.length);
77 CodeBuilderUtils.constructRecord(closureClass, mb, parameterTypes, parameters);
78 return Types.function(Arrays.copyOfRange(parameterTypes, parameters.length, parameterTypes.length), returnType);
80 else if(parameters.length > arity) {
81 Type returnType = applyExact(mb, Arrays.copyOf(parameters, arity));
82 mb.pushBoxed(Arrays.copyOfRange(parameters, arity, parameters.length));
83 int remainingArity = parameters.length - arity;
84 mb.genericApply(remainingArity);
86 if(typeParameters.length > 0)
87 returnType = returnType.replace(this.typeParameters, typeParameters);
89 returnType = BTypes.matchFunction(returnType, remainingArity)[remainingArity];
90 } catch (MatchException e) {
91 throw new InternalCompilerError("Tried to apply value of type " + returnType + " with " + remainingArity + " parameters.");
97 return applyExact(mb, parameters);
101 public abstract Type applyExact(MethodBuilder mb, Val[] parameters);
104 public int getEffectiveArity() {
105 return parameterTypes.length;
110 public Object realizeValue(TransientClassBuilder builder) {
111 THashMap<Constant, Object> valueCache = builder.classLoader.getConstantCache();
112 if(valueCache != null) {
113 Object cachedResult = valueCache.get(this);
114 if(cachedResult != null)
118 int arity = getEffectiveArity();
120 return super.realizeValue(builder);
122 String packageName = builder.classLoader.getFreshPackageName();
123 String moduleName = packageName + "/Temp";
124 JavaNamingPolicy policy = new JavaNamingPolicy(moduleName);
125 ModuleBuilder moduleBuilder = new ModuleBuilder(policy, builder.javaTypeTranslator);
127 ClassBuilder classFile;
128 if(arity <= Constants.MAX_FUNCTION_PARAMETER_COUNT) {
129 if(SCLCompilerConfiguration.TRACE_METHOD_CREATION)
130 System.out.println("Create class " + policy.getModuleClassName());
131 classFile = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, policy.getModuleClassName(),
132 MethodBuilderBase.getClassName(Constants.FUNCTION_IMPL[arity]));
133 classFile.setSourceFile("_SCL_FunctionValue");
134 classFile.addDefaultConstructor();
136 MethodBuilder mb =classFile.addMethod(Opcodes.ACC_PUBLIC, "apply", TypeDesc.OBJECT, Constants.OBJECTS[arity]);
137 Val[] parameters = new Val[arity];
138 for(int i=0;i<arity;++i)
139 parameters[i] = new LocalVariableConstant(parameterTypes[i], mb.getParameter(i));
141 mb.box(applyExact(mb, parameters));
142 mb.returnValue(TypeDesc.OBJECT);
146 if(SCLCompilerConfiguration.TRACE_METHOD_CREATION)
147 System.out.println("Create class " + policy.getModuleClassName());
148 classFile = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, policy.getModuleClassName(),
149 MethodBuilderBase.getClassName(Constants.FUNCTION_N_IMPL));
150 classFile.setSourceFile("_SCL_FunctionValue");
154 MethodBuilderBase mb = classFile.addConstructorBase(Opcodes.ACC_PUBLIC, Constants.EMPTY_TYPEDESC_ARRAY);
156 mb.loadConstant(arity);
157 mb.invokeConstructor(MethodBuilderBase.getClassName(Constants.FUNCTION_N_IMPL), new TypeDesc[] {TypeDesc.INT});
163 MethodBuilder mb = classFile.addMethod(Opcodes.ACC_PUBLIC, "doApply", TypeDesc.OBJECT,
164 new TypeDesc[] {TypeDesc.forClass(Object[].class)});
165 Val[] parameters = new Val[arity];
166 for(int i=0;i<arity;++i)
167 parameters[i] = new LocalBoxedArrayElementConstant(parameterTypes[i],
168 mb.getParameter(0), i);
169 applyExact(mb, parameters);
171 mb.returnValue(TypeDesc.OBJECT);
175 /* Add a toString() method that returns the function name */
176 MethodBuilder mb2 = classFile.addMethod(Opcodes.ACC_PUBLIC, "toString", TypeDesc.STRING, Constants.OBJECTS[0]);
177 mb2.loadConstant(this.toString());
178 mb2.returnValue(TypeDesc.STRING);
181 moduleBuilder.addClass(classFile);
183 MutableClassLoader classLoader = builder.classLoader;
184 classLoader.addClasses(moduleBuilder.getClasses());
186 Object result = classLoader.loadClass(policy.getModuleClassName().replace('/', '.')).newInstance();
187 if(valueCache != null) {
188 valueCache.put(this, result);
189 if(TRACE_REALIZATION)
190 System.out.println("/REALIZED/ " + this + " " + getClass().getSimpleName());
193 } catch (InstantiationException e) {
194 throw new InternalCompilerError(e);
195 } catch (IllegalAccessException e) {
196 throw new InternalCompilerError(e);
197 } catch (ClassNotFoundException e) {
198 throw new InternalCompilerError(e);