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;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
19 import gnu.trove.map.hash.THashMap;
21 public class ModuleBuilder {
23 private static final Logger LOGGER = LoggerFactory.getLogger(ModuleBuilder.class);
25 JavaNamingPolicy namingPolicy;
26 JavaTypeTranslator javaTypeTranslator;
28 THashMap<String, byte[]> classes = new THashMap<String, byte[]>();
30 THashMap<ClosureDesc, TypeDesc> cache = new THashMap<ClosureDesc, TypeDesc>();
32 MethodSizeCounter methodSizeCounter;
34 public void addClass(ClassBuilder cb) {
35 byte[] bytecode = cb.finishClass();
36 classes.put(cb.getClassName(), bytecode);
37 //LOGGER.info("Added " + cb.getClassName());
40 public JavaTypeTranslator getJavaTypeTranslator() {
41 return javaTypeTranslator;
44 static class ClosureDesc {
45 FunctionValue functionValue;
46 int knownParametersCount;
48 public ClosureDesc(FunctionValue functionValue, int knownParametersCount) {
49 this.functionValue = functionValue;
50 this.knownParametersCount = knownParametersCount;
54 public int hashCode() {
55 return functionValue.hashCode() + 31 * knownParametersCount;
59 public boolean equals(Object obj) {
62 if(obj == null || obj.getClass() != getClass())
64 ClosureDesc other = (ClosureDesc)obj;
65 return functionValue == other.functionValue && knownParametersCount == other.knownParametersCount;
69 public ModuleBuilder(JavaNamingPolicy namingPolicy, JavaTypeTranslator javaTypeTranslator) {
70 this.namingPolicy = namingPolicy;
71 this.javaTypeTranslator = javaTypeTranslator;
74 public TypeDesc getClosure(FunctionValue functionValue, int knownParametersCount) {
75 ClosureDesc desc = new ClosureDesc(functionValue, knownParametersCount);
76 TypeDesc result = cache.get(desc);
78 result = createClosure(functionValue, knownParametersCount);
79 cache.put(desc, result);
84 private TypeDesc createClosure(FunctionValue functionValue, int knownParametersCount) {
85 String className = namingPolicy.getFreshClosureClassName();
87 int remainingArity = functionValue.getArity() - knownParametersCount;
88 TypeDesc[] parameterTypes = javaTypeTranslator.toTypeDescs(functionValue.getParameterTypes());
91 ClassBuilder classBuilder;
92 if(remainingArity <= Constants.MAX_FUNCTION_PARAMETER_COUNT) {
93 if(SCLCompilerConfiguration.TRACE_METHOD_CREATION)
94 LOGGER.info("Create class " + className);
95 classBuilder = new ClassBuilder(this, Opcodes.ACC_PUBLIC, className, MethodBuilderBase.getClassName(Constants.FUNCTION_IMPL[remainingArity]));
96 classBuilder.setSourceFile("_SCL_Closure");
99 CodeBuilderUtils.makeRecord(classBuilder, functionValue.toString(), Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "p",
100 Arrays.copyOf(parameterTypes, knownParametersCount),
105 MethodBuilder mb = classBuilder.addMethod(Opcodes.ACC_PUBLIC, "apply", TypeDesc.OBJECT, Constants.OBJECTS[remainingArity]);
106 Val[] parameters = new Val[functionValue.getArity()];
107 for(int i=0;i<knownParametersCount;++i)
108 parameters[i] = new LocalFieldConstant(functionValue.getParameterTypes()[i], "p"+i);
109 for(int i=0;i<remainingArity;++i) {
110 Type type = functionValue.getParameterTypes()[knownParametersCount+i];
111 parameters[knownParametersCount+i] = new LocalVariableConstant(type, mb.getParameter(i));
113 functionValue.prepare(mb);
114 Type returnType = functionValue.applyExact(mb, parameters);
116 mb.returnValue(TypeDesc.OBJECT);
121 if(SCLCompilerConfiguration.TRACE_METHOD_CREATION)
122 LOGGER.info("Create class " + className);
123 classBuilder = new ClassBuilder(this, Opcodes.ACC_PUBLIC, className, MethodBuilderBase.getClassName(Constants.FUNCTION_N_IMPL));
124 classBuilder.setSourceFile("_SCL_Closure");
127 for(int i=0;i<knownParametersCount;++i)
128 classBuilder.addField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "p"+i, parameterTypes[i]);
130 // Create constructor
132 MethodBuilderBase mb = classBuilder.addConstructorBase(Opcodes.ACC_PUBLIC, Arrays.copyOf(parameterTypes, knownParametersCount));
134 mb.loadConstant(remainingArity);
135 mb.invokeConstructor(MethodBuilderBase.getClassName(Constants.FUNCTION_N_IMPL), new TypeDesc[] { TypeDesc.INT });
136 for(int i=0;i<knownParametersCount;++i) {
138 mb.loadLocal(mb.getParameter(i));
139 mb.storeField(className, "p"+i, parameterTypes[i]);
147 MethodBuilder mb = classBuilder.addMethod(Opcodes.ACC_PUBLIC, "doApply", TypeDesc.OBJECT, new TypeDesc[] {TypeDesc.forClass(Object[].class)});
148 Val[] parameters = new Val[functionValue.getArity()];
149 for(int i=0;i<knownParametersCount;++i)
150 parameters[i] = new LocalFieldConstant(functionValue.getParameterTypes()[i], "p"+i);
151 LocalVariable parameter = mb.getParameter(0);
152 for(int i=0;i<remainingArity;++i) {
153 mb.loadLocal(parameter);
155 mb.loadFromArray(TypeDesc.OBJECT);
156 Type type = functionValue.getParameterTypes()[knownParametersCount+i];
157 TypeDesc typeDesc = javaTypeTranslator.toTypeDesc(type);
159 LocalVariable lv = mb.createLocalVariable("p"+(i+knownParametersCount), typeDesc);
161 BoundVar var = new BoundVar(type);
162 parameters[knownParametersCount+i] = var;
163 mb.setLocalVariable(var, lv);
165 functionValue.applyExact(mb, parameters);
166 mb.box(functionValue.getReturnType());
167 mb.returnValue(TypeDesc.OBJECT);
170 CodeBuilderUtils.implementHashCodeAndEquals(classBuilder, functionValue.toString(), "p", parameterTypes);
174 addClass(classBuilder);
176 return TypeDesc.forClass(className);
179 public Map<String, byte[]> getClasses() {
183 public JavaNamingPolicy getNamingPolicy() {
187 public MethodSizeCounter getMethodSizeCounter() {
188 return methodSizeCounter;