]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/ModuleBuilder.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / utils / ModuleBuilder.java
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 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 import gnu.trove.map.hash.THashMap;
20
21 public class ModuleBuilder {
22
23     private static final Logger LOGGER = LoggerFactory.getLogger(ModuleBuilder.class);
24
25     JavaNamingPolicy namingPolicy;
26     JavaTypeTranslator javaTypeTranslator;
27     
28     THashMap<String, byte[]> classes = new THashMap<String, byte[]>(); 
29
30     THashMap<ClosureDesc, TypeDesc> cache = new THashMap<ClosureDesc, TypeDesc>();
31     
32     MethodSizeCounter methodSizeCounter;
33     
34     public void addClass(ClassBuilder cb) {
35         byte[] bytecode = cb.finishClass();
36         classes.put(cb.getClassName(), bytecode);
37         //LOGGER.info("Added " + cb.getClassName());
38     }
39     
40     public JavaTypeTranslator getJavaTypeTranslator() {
41         return javaTypeTranslator;
42     }
43         
44     static class ClosureDesc {
45         FunctionValue functionValue;
46         int knownParametersCount;
47         
48         public ClosureDesc(FunctionValue functionValue, int knownParametersCount) {
49             this.functionValue = functionValue;
50             this.knownParametersCount = knownParametersCount;
51         }
52         
53         @Override
54         public int hashCode() {
55             return functionValue.hashCode() + 31 * knownParametersCount;
56         }
57         
58         @Override
59         public boolean equals(Object obj) {
60             if(this == obj)
61                 return true;
62             if(obj == null || obj.getClass() != getClass())
63                 return false;
64             ClosureDesc other = (ClosureDesc)obj;
65             return functionValue == other.functionValue && knownParametersCount == other.knownParametersCount;
66         }        
67     }
68     
69     public ModuleBuilder(JavaNamingPolicy namingPolicy, JavaTypeTranslator javaTypeTranslator) {
70         this.namingPolicy = namingPolicy;
71         this.javaTypeTranslator = javaTypeTranslator;
72     }
73
74     public TypeDesc getClosure(FunctionValue functionValue, int knownParametersCount) {
75         ClosureDesc desc = new ClosureDesc(functionValue, knownParametersCount);
76         TypeDesc result = cache.get(desc);
77         if(result == null) {
78             result = createClosure(functionValue, knownParametersCount);
79             cache.put(desc, result);
80         }
81         return result;
82     }
83
84     private TypeDesc createClosure(FunctionValue functionValue, int knownParametersCount) {
85         String className = namingPolicy.getFreshClosureClassName();
86         
87         int remainingArity = functionValue.getArity() - knownParametersCount;
88         TypeDesc[] parameterTypes = javaTypeTranslator.toTypeDescs(functionValue.getParameterTypes());
89         
90         // Create new class
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");
97             
98             // Create fields
99             CodeBuilderUtils.makeRecord(classBuilder, functionValue.toString(), Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "p",
100                     Arrays.copyOf(parameterTypes, knownParametersCount),
101                     true);
102             
103             // Create apply
104             {
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));
112                 }
113                 functionValue.prepare(mb);
114                 Type returnType = functionValue.applyExact(mb, parameters);
115                 mb.box(returnType);
116                 mb.returnValue(TypeDesc.OBJECT);
117                 mb.finish();
118             }        
119         }
120         else {
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");
125             
126             // Create fields
127             for(int i=0;i<knownParametersCount;++i)
128                 classBuilder.addField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "p"+i, parameterTypes[i]);
129             
130             // Create constructor
131             {
132                 MethodBuilderBase mb = classBuilder.addConstructorBase(Opcodes.ACC_PUBLIC, Arrays.copyOf(parameterTypes, knownParametersCount));
133                 mb.loadThis();
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) {
137                     mb.loadThis();
138                     mb.loadLocal(mb.getParameter(i));
139                     mb.storeField(className, "p"+i, parameterTypes[i]);
140                 }
141                 mb.returnVoid();
142                 mb.finish();
143             }
144             
145             // Create apply
146             {
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);
154                     mb.loadConstant(i);
155                     mb.loadFromArray(TypeDesc.OBJECT);
156                     Type type = functionValue.getParameterTypes()[knownParametersCount+i];
157                     TypeDesc typeDesc = javaTypeTranslator.toTypeDesc(type);
158                     mb.unbox(type);
159                     LocalVariable lv = mb.createLocalVariable("p"+(i+knownParametersCount), typeDesc);
160                     mb.storeLocal(lv);
161                     BoundVar var = new BoundVar(type);
162                     parameters[knownParametersCount+i] = var;
163                     mb.setLocalVariable(var, lv);
164                 }
165                 functionValue.applyExact(mb, parameters);
166                 mb.box(functionValue.getReturnType());
167                 mb.returnValue(TypeDesc.OBJECT);
168             }
169             
170             CodeBuilderUtils.implementHashCodeAndEquals(classBuilder, functionValue.toString(), "p", parameterTypes);
171         }
172             
173         // Finish
174         addClass(classBuilder);
175         
176         return TypeDesc.forClass(className);
177     }
178     
179     public Map<String, byte[]> getClasses() {
180         return classes;
181     }
182     
183     public JavaNamingPolicy getNamingPolicy() {
184         return namingPolicy;
185     }
186     
187     public MethodSizeCounter getMethodSizeCounter() {
188         return methodSizeCounter;
189     }
190 }