]> gerrit.simantics Code Review - simantics/platform.git/blob
8db288a8976196486ec14ee0601ddbf4a14575b8
[simantics/platform.git] /
1 package org.simantics.scl.compiler.internal.codegen.utils;
2
3 import java.util.Arrays;
4 import java.util.Map;
5
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
17 import gnu.trove.map.hash.THashMap;
18
19 public class ModuleBuilder {
20     JavaNamingPolicy namingPolicy;
21     JavaTypeTranslator javaTypeTranslator;
22     
23     THashMap<String, byte[]> classes = new THashMap<String, byte[]>(); 
24
25     THashMap<ClosureDesc, TypeDesc> cache = new THashMap<ClosureDesc, TypeDesc>();
26     
27     MethodSizeCounter methodSizeCounter;
28     
29     public void addClass(ClassBuilder cb) {
30         byte[] bytecode = cb.finishClass();
31         classes.put(cb.getClassName(), bytecode);
32         //System.out.println("Added " + cb.getClassName());
33     }
34     
35     public JavaTypeTranslator getJavaTypeTranslator() {
36         return javaTypeTranslator;
37     }
38         
39     static class ClosureDesc {
40         FunctionValue functionValue;
41         int knownParametersCount;
42         
43         public ClosureDesc(FunctionValue functionValue, int knownParametersCount) {
44             this.functionValue = functionValue;
45             this.knownParametersCount = knownParametersCount;
46         }
47         
48         @Override
49         public int hashCode() {
50             return functionValue.hashCode() + 31 * knownParametersCount;
51         }
52         
53         @Override
54         public boolean equals(Object obj) {
55             if(this == obj)
56                 return true;
57             if(obj == null || obj.getClass() != getClass())
58                 return false;
59             ClosureDesc other = (ClosureDesc)obj;
60             return functionValue == other.functionValue && knownParametersCount == other.knownParametersCount;
61         }        
62     }
63     
64     public ModuleBuilder(JavaNamingPolicy namingPolicy, JavaTypeTranslator javaTypeTranslator) {
65         this.namingPolicy = namingPolicy;
66         this.javaTypeTranslator = javaTypeTranslator;
67     }
68
69     public TypeDesc getClosure(FunctionValue functionValue, int knownParametersCount) {
70         ClosureDesc desc = new ClosureDesc(functionValue, knownParametersCount);
71         TypeDesc result = cache.get(desc);
72         if(result == null) {
73             result = createClosure(functionValue, knownParametersCount);
74             cache.put(desc, result);
75         }
76         return result;
77     }
78
79     private TypeDesc createClosure(FunctionValue functionValue, int knownParametersCount) {
80         String className = namingPolicy.getFreshClosureClassName();
81         
82         int remainingArity = functionValue.getArity() - knownParametersCount;
83         TypeDesc[] parameterTypes = javaTypeTranslator.toTypeDescs(functionValue.getParameterTypes());
84         
85         // Create new class
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");
92             
93             // Create fields
94             CodeBuilderUtils.makeRecord(classBuilder, functionValue.toString(), Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "p",
95                     Arrays.copyOf(parameterTypes, knownParametersCount),
96                     true);
97             
98             // Create apply
99             {
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));
107                 }
108                 functionValue.prepare(mb);
109                 Type returnType = functionValue.applyExact(mb, parameters);
110                 mb.box(returnType);
111                 mb.returnValue(TypeDesc.OBJECT);
112                 mb.finish();
113             }        
114         }
115         else {
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");
120             
121             // Create fields
122             for(int i=0;i<knownParametersCount;++i)
123                 classBuilder.addField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "p"+i, parameterTypes[i]);
124             
125             // Create constructor
126             {
127                 MethodBuilderBase mb = classBuilder.addConstructor(Opcodes.ACC_PUBLIC, Arrays.copyOf(parameterTypes, knownParametersCount));
128                 mb.loadThis();
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) {
132                     mb.loadThis();
133                     mb.loadLocal(mb.getParameter(i));
134                     mb.storeField(className, "p"+i, parameterTypes[i]);
135                 }
136                 mb.returnVoid();
137                 mb.finish();
138             }
139             
140             // Create apply
141             {
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);
149                     mb.loadConstant(i);
150                     mb.loadFromArray(TypeDesc.OBJECT);
151                     Type type = functionValue.getParameterTypes()[knownParametersCount+i];
152                     TypeDesc typeDesc = javaTypeTranslator.toTypeDesc(type);
153                     mb.unbox(type);
154                     LocalVariable lv = mb.createLocalVariable("p"+(i+knownParametersCount), typeDesc);
155                     mb.storeLocal(lv);
156                     BoundVar var = new BoundVar(type);
157                     parameters[knownParametersCount+i] = var;
158                     mb.setLocalVariable(var, lv);
159                 }
160                 functionValue.applyExact(mb, parameters);
161                 mb.box(functionValue.getReturnType());
162                 mb.returnValue(TypeDesc.OBJECT);
163             }
164             
165             CodeBuilderUtils.implementHashCodeAndEquals(classBuilder, functionValue.toString(), "p", parameterTypes);
166         }
167             
168         // Finish
169         addClass(classBuilder);
170         
171         return TypeDesc.forClass(className);
172     }
173     
174     public Map<String, byte[]> getClasses() {
175         return classes;
176     }
177     
178     public JavaNamingPolicy getNamingPolicy() {
179         return namingPolicy;
180     }
181     
182     public MethodSizeCounter getMethodSizeCounter() {
183         return methodSizeCounter;
184     }
185 }