]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/MethodBuilder.java
(refs #7414) Added Dynamic constructor
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / utils / MethodBuilder.java
1 package org.simantics.scl.compiler.internal.codegen.utils;
2
3 import org.cojen.classfile.TypeDesc;
4 import org.objectweb.asm.Label;
5 import org.objectweb.asm.MethodVisitor;
6 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
7 import org.simantics.scl.compiler.constants.LocalVariableConstant;
8 import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
9 import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;
10 import org.simantics.scl.compiler.internal.codegen.continuations.ReturnCont;
11 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
12 import org.simantics.scl.compiler.internal.codegen.references.IVal;
13 import org.simantics.scl.compiler.internal.codegen.references.Val;
14 import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock;
15 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
16 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
17 import org.simantics.scl.compiler.types.TVar;
18 import org.simantics.scl.compiler.types.Type;
19 import org.simantics.scl.compiler.types.Types;
20
21 import gnu.trove.map.hash.THashMap;
22 import gnu.trove.set.hash.THashSet;
23
24 public class MethodBuilder extends MethodBuilderBase {
25     ModuleBuilder moduleBuilder;
26     THashMap<Cont, Label> labels = new THashMap<Cont, Label>();
27     THashMap<BoundVar, LocalVariable> localVariables = new THashMap<BoundVar, LocalVariable>();
28     THashSet<Cont> generatedConts = new THashSet<Cont>();
29     THashMap<Object,Object> preparationSteps = new THashMap<Object,Object>(4); 
30     
31     public MethodBuilder(ClassBuilder classBuilder, ModuleBuilder moduleBuilder, boolean isStatic, MethodVisitor methodVisitor, TypeDesc[] parameterTypes) {
32         super(classBuilder, isStatic, methodVisitor, parameterTypes);
33         this.moduleBuilder = moduleBuilder;
34     }
35     
36     public JavaTypeTranslator getJavaTypeTranslator() {
37         return getModuleBuilder().getJavaTypeTranslator();
38     }
39     
40     public ModuleBuilder getModuleBuilder() {
41         return moduleBuilder;
42     }
43     
44     public void push(IVal val, Type type) {
45         val.push(this);
46         if(Types.canonical(type) instanceof TVar)
47             box(val.getType());
48     }
49             
50     public void push(Val[] vals, Type[] types) {
51         assert(vals.length == types.length);
52         for(int i=0;i<vals.length;++i)
53             push(vals[i], types[i]);
54     }
55         
56     public void pushBoxed(Val val) {
57         val.push(this);
58         box(val.getType());
59     }
60     
61     public void pushBoxed(Val[] vals) {
62         for(Val val : vals)
63             pushBoxed(val);
64     }
65
66     public void genericApply(int arity) {
67         invokeInterface(Constants.FUNCTION, "apply", TypeDesc.OBJECT, Constants.OBJECTS[arity]);
68     }
69     
70     public void pushTuple0() {
71         loadStaticField(Constants.TUPLE0, "INSTANCE", Constants.TUPLE0);
72     }
73     
74     private void boxPrimitiveType(TypeDesc primitiveType) {
75         if(primitiveType.equals(TypeDesc.VOID)) {            
76             pushTuple0();
77         }
78         else {
79             TypeDesc objectType = primitiveType.toObjectType();
80             invokeStatic(getClassName(objectType), "valueOf", 
81                     objectType, new TypeDesc[] {primitiveType});
82         }
83     }
84     
85     /**
86      * Boxes the top of the stack.
87      */
88     public void box(Type type) {
89         TypeDesc typeDesc = getJavaTypeTranslator().toTypeDesc(type);
90         if(typeDesc.isPrimitive()) {
91             boxPrimitiveType(typeDesc);
92         }
93         //codeBuilder.convert(typeDesc, TypeDesc.OBJECT);
94     }
95
96     /**
97      * Unboxes the top of the stack.
98      */
99     public void unbox(Type type) {
100         TypeDesc td = getJavaTypeTranslator().toTypeDesc(type);
101         if(td.equals(TypeDesc.VOID)) {
102             pop();
103             return;
104         }
105         if(td.isPrimitive()) {
106             TypeDesc objectType = td.toObjectType();
107             checkCast(objectType);
108             convert(objectType, td);
109         }
110         else {
111             if(td != TypeDesc.OBJECT)
112                 checkCast(td);
113         }
114     }
115
116     public void setLocation(Cont continuation) {
117         setLocation(getLabel(continuation));   
118         if(!generatedConts.add(continuation))
119             throw new InternalCompilerError("Label location is set multiple times");
120     }
121     
122     public Label getLabel(Cont continuation) {
123         Label label = labels.get(continuation);
124         if(label == null) {
125             label = createLabel();
126             labels.put(continuation, label);
127         }
128         return label;
129     }
130     
131     public void setLocalVariable(BoundVar var, LocalVariable localVariable) {
132         localVariables.put(var, localVariable);
133     }
134
135     public LocalVariable getLocalVariable(BoundVar var) {
136         LocalVariable localVariable = localVariables.get(var);
137         if(localVariable == null) {
138             TypeDesc typeDesc = getJavaTypeTranslator().getTypeDesc(var);
139             if(SCLCompilerConfiguration.DEBUG) {
140                 if(typeDesc.equals(TypeDesc.VOID))
141                     throw new InternalCompilerError();
142             }
143             localVariable = createLocalVariable(null, typeDesc);
144             localVariables.put(var, localVariable);
145         }
146         return localVariable;
147     }
148
149     public void jump(ContRef target) {
150         jump(target.getBinding());
151     }
152
153     public void jump(ContRef target, Val ... parameters) {
154         jump(target.getBinding(), parameters);
155     }
156     
157     public void jump(Cont cont) {
158         if(cont instanceof SSABlock) {
159             SSABlock block = (SSABlock)cont;
160             if(generatedConts.contains(block))
161                 branch(getLabel(block));
162             else            
163                 block.generateCode(this);
164         }
165         else
166             throw new InternalCompilerError();
167     }
168             
169     public void jump(Cont cont, IVal ... parameters) {
170         if(cont instanceof ReturnCont) {
171             ReturnCont returnCont = (ReturnCont)cont;
172             if(parameters.length != 1)
173                 throw new InternalCompilerError();
174             push(parameters[0], returnCont.getType());
175             //parameters[0].push(this);
176             returnValue(getJavaTypeTranslator().toTypeDesc(returnCont.getType()));
177         }
178         else if(cont instanceof SSABlock) {
179             SSABlock block = (SSABlock)cont;
180             BoundVar[] parameterVars = block.getParameters();
181             if(parameters.length != parameterVars.length)
182                 throw new InternalCompilerError();
183             // First calculate all parameters and push them into stack
184             for(int i=0;i<parameters.length;++i)
185                 if(parameters[i] != parameterVars[i]) {
186                     push(parameters[i], parameterVars[i].getType());
187                     //parameters[i].push(this);
188                 }
189             // Then store them to the local variables
190             // NOTE: some computations inside pushs may depend on these variables
191             for(int i=parameters.length-1;i>=0;--i)
192                 if(parameters[i] != parameterVars[i])
193                     store(parameterVars[i]);
194             if(generatedConts.contains(block))
195                 branch(getLabel(block));
196             else            
197                 block.generateCode(this);
198         }
199         else
200             throw new InternalCompilerError();
201     }
202
203     public void store(BoundVar var) {
204         Type type = var.getType();
205         TypeDesc typeDesc = getJavaTypeTranslator().toTypeDesc(type);
206         if(typeDesc.equals(TypeDesc.VOID))
207             return;
208         LocalVariable lv = getLocalVariable(var);
209         storeLocal(lv);
210     }
211
212     /**
213      * Generates the continuation code if it does not already exist.
214      */
215     public void ensureExists(Cont continuation) {
216         if(!generatedConts.contains(continuation))
217             ((SSABlock)continuation).generateCode(this);
218     }
219     
220     @SuppressWarnings("unchecked")
221     public <T> T getPreparation(PreparationStep<T> step) {
222         return (T)preparationSteps.get(step);
223     }
224     
225     public <T> void addPreparation(PreparationStep<T> step, T result) {
226         preparationSteps.put(step, result);
227     }
228
229     public LocalVariable cacheValue(IVal val, Type type) {
230         if(val instanceof BoundVar) {
231             BoundVar boundVar = (BoundVar)val;
232             if(!boundVar.generateOnFly)
233                 return getLocalVariable(boundVar);
234         }
235         else if(val instanceof LocalVariableConstant) {
236             return ((LocalVariableConstant)val).var;
237         }
238         push(val, type);
239         LocalVariable temp = createLocalVariable(null, getJavaTypeTranslator().toTypeDesc(type));
240         storeLocal(temp);
241         return temp;
242     }
243 }