1 package org.simantics.scl.compiler.internal.codegen.utils;
3 import java.util.Arrays;
6 import org.cojen.classfile.TypeDesc;
7 import org.objectweb.asm.Opcodes;
8 import org.simantics.scl.compiler.constants.FunctionValue;
9 import org.simantics.scl.compiler.constants.LocalFieldConstant;
10 import org.simantics.scl.compiler.constants.LocalVariableConstant;
11 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
12 import org.simantics.scl.compiler.internal.codegen.references.Val;
13 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
14 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
15 import org.simantics.scl.compiler.types.Type;
17 import gnu.trove.map.hash.THashMap;
19 public class ModuleBuilder {
20 JavaNamingPolicy namingPolicy;
21 JavaTypeTranslator javaTypeTranslator;
23 THashMap<String, byte[]> classes = new THashMap<String, byte[]>();
25 THashMap<ClosureDesc, TypeDesc> cache = new THashMap<ClosureDesc, TypeDesc>();
27 MethodSizeCounter methodSizeCounter;
29 public void addClass(ClassBuilder cb) {
30 byte[] bytecode = cb.finishClass();
31 classes.put(cb.getClassName(), bytecode);
32 //System.out.println("Added " + cb.getClassName());
35 public JavaTypeTranslator getJavaTypeTranslator() {
36 return javaTypeTranslator;
39 static class ClosureDesc {
40 FunctionValue functionValue;
41 int knownParametersCount;
43 public ClosureDesc(FunctionValue functionValue, int knownParametersCount) {
44 this.functionValue = functionValue;
45 this.knownParametersCount = knownParametersCount;
49 public int hashCode() {
50 return functionValue.hashCode() + 31 * knownParametersCount;
54 public boolean equals(Object obj) {
57 if(obj == null || obj.getClass() != getClass())
59 ClosureDesc other = (ClosureDesc)obj;
60 return functionValue == other.functionValue && knownParametersCount == other.knownParametersCount;
64 public ModuleBuilder(JavaNamingPolicy namingPolicy, JavaTypeTranslator javaTypeTranslator) {
65 this.namingPolicy = namingPolicy;
66 this.javaTypeTranslator = javaTypeTranslator;
69 public TypeDesc getClosure(FunctionValue functionValue, int knownParametersCount) {
70 ClosureDesc desc = new ClosureDesc(functionValue, knownParametersCount);
71 TypeDesc result = cache.get(desc);
73 result = createClosure(functionValue, knownParametersCount);
74 cache.put(desc, result);
79 private TypeDesc createClosure(FunctionValue functionValue, int knownParametersCount) {
80 String className = namingPolicy.getFreshClosureClassName();
82 int remainingArity = functionValue.getArity() - knownParametersCount;
83 TypeDesc[] parameterTypes = javaTypeTranslator.toTypeDescs(functionValue.getParameterTypes());
86 ClassBuilder classBuilder;
87 if(remainingArity <= Constants.MAX_FUNCTION_PARAMETER_COUNT) {
88 if(SCLCompilerConfiguration.TRACE_METHOD_CREATION)
89 System.out.println("Create class " + className);
90 classBuilder = new ClassBuilder(this, Opcodes.ACC_PUBLIC, className, MethodBuilderBase.getClassName(Constants.FUNCTION_IMPL[remainingArity]));
91 classBuilder.setSourceFile("_SCL_Closure");
94 CodeBuilderUtils.makeRecord(classBuilder, functionValue.toString(), Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "p",
95 Arrays.copyOf(parameterTypes, knownParametersCount),
100 MethodBuilder mb = classBuilder.addMethod(Opcodes.ACC_PUBLIC, "apply", TypeDesc.OBJECT, Constants.OBJECTS[remainingArity]);
101 Val[] parameters = new Val[functionValue.getArity()];
102 for(int i=0;i<knownParametersCount;++i)
103 parameters[i] = new LocalFieldConstant(functionValue.getParameterTypes()[i], "p"+i);
104 for(int i=0;i<remainingArity;++i) {
105 Type type = functionValue.getParameterTypes()[knownParametersCount+i];
106 parameters[knownParametersCount+i] = new LocalVariableConstant(type, mb.getParameter(i));
108 functionValue.prepare(mb);
109 Type returnType = functionValue.applyExact(mb, parameters);
111 mb.returnValue(TypeDesc.OBJECT);
116 if(SCLCompilerConfiguration.TRACE_METHOD_CREATION)
117 System.out.println("Create class " + className);
118 classBuilder = new ClassBuilder(this, Opcodes.ACC_PUBLIC, className, MethodBuilderBase.getClassName(Constants.FUNCTION_N_IMPL));
119 classBuilder.setSourceFile("_SCL_Closure");
122 for(int i=0;i<knownParametersCount;++i)
123 classBuilder.addField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "p"+i, parameterTypes[i]);
125 // Create constructor
127 MethodBuilderBase mb = classBuilder.addConstructor(Opcodes.ACC_PUBLIC, Arrays.copyOf(parameterTypes, knownParametersCount));
129 mb.loadConstant(remainingArity);
130 mb.invokeConstructor(MethodBuilderBase.getClassName(Constants.FUNCTION_N_IMPL), new TypeDesc[] { TypeDesc.INT });
131 for(int i=0;i<knownParametersCount;++i) {
133 mb.loadLocal(mb.getParameter(i));
134 mb.storeField(className, "p"+i, parameterTypes[i]);
142 MethodBuilder mb = classBuilder.addMethod(Opcodes.ACC_PUBLIC, "doApply", TypeDesc.OBJECT, new TypeDesc[] {TypeDesc.forClass(Object[].class)});
143 Val[] parameters = new Val[functionValue.getArity()];
144 for(int i=0;i<knownParametersCount;++i)
145 parameters[i] = new LocalFieldConstant(functionValue.getParameterTypes()[i], "p"+i);
146 LocalVariable parameter = mb.getParameter(0);
147 for(int i=0;i<remainingArity;++i) {
148 mb.loadLocal(parameter);
150 mb.loadFromArray(TypeDesc.OBJECT);
151 Type type = functionValue.getParameterTypes()[knownParametersCount+i];
152 TypeDesc typeDesc = javaTypeTranslator.toTypeDesc(type);
154 LocalVariable lv = mb.createLocalVariable("p"+(i+knownParametersCount), typeDesc);
156 BoundVar var = new BoundVar(type);
157 parameters[knownParametersCount+i] = var;
158 mb.setLocalVariable(var, lv);
160 functionValue.applyExact(mb, parameters);
161 mb.box(functionValue.getReturnType());
162 mb.returnValue(TypeDesc.OBJECT);
165 CodeBuilderUtils.implementHashCodeAndEquals(classBuilder, functionValue.toString(), "p", parameterTypes);
169 addClass(classBuilder);
171 return TypeDesc.forClass(className);
174 public Map<String, byte[]> getClasses() {
178 public JavaNamingPolicy getNamingPolicy() {
182 public MethodSizeCounter getMethodSizeCounter() {
183 return methodSizeCounter;