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