1 package org.simantics.scl.compiler.internal.codegen.utils;
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;
21 import gnu.trove.map.hash.THashMap;
22 import gnu.trove.set.hash.THashSet;
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);
31 public MethodBuilder(ClassBuilder classBuilder, ModuleBuilder moduleBuilder, boolean isStatic, MethodVisitor methodVisitor, TypeDesc[] parameterTypes) {
32 super(classBuilder, isStatic, methodVisitor, parameterTypes);
33 this.moduleBuilder = moduleBuilder;
36 public JavaTypeTranslator getJavaTypeTranslator() {
37 return getModuleBuilder().getJavaTypeTranslator();
40 public ModuleBuilder getModuleBuilder() {
44 public void push(IVal val, Type type) {
46 if(Types.canonical(type) instanceof TVar)
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]);
56 public void pushBoxed(Val val) {
61 public void pushBoxed(Val[] vals) {
66 public void genericApply(int arity) {
67 invokeInterface(Constants.FUNCTION, "apply", TypeDesc.OBJECT, Constants.OBJECTS[arity]);
70 public void pushTuple0() {
71 loadStaticField(Constants.TUPLE0, "INSTANCE", Constants.TUPLE0);
74 private void boxPrimitiveType(TypeDesc primitiveType) {
75 if(primitiveType.equals(TypeDesc.VOID)) {
79 TypeDesc objectType = primitiveType.toObjectType();
80 invokeStatic(getClassName(objectType), "valueOf",
81 objectType, new TypeDesc[] {primitiveType});
86 * Boxes the top of the stack.
88 public void box(Type type) {
89 TypeDesc typeDesc = getJavaTypeTranslator().toTypeDesc(type);
90 if(typeDesc.isPrimitive()) {
91 boxPrimitiveType(typeDesc);
93 //codeBuilder.convert(typeDesc, TypeDesc.OBJECT);
97 * Unboxes the top of the stack.
99 public void unbox(Type type) {
100 TypeDesc td = getJavaTypeTranslator().toTypeDesc(type);
101 if(td.equals(TypeDesc.VOID)) {
105 if(td.isPrimitive()) {
106 TypeDesc objectType = td.toObjectType();
107 checkCast(objectType);
108 convert(objectType, td);
111 if(td != TypeDesc.OBJECT)
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");
122 public Label getLabel(Cont continuation) {
123 Label label = labels.get(continuation);
125 label = createLabel();
126 labels.put(continuation, label);
131 public void setLocalVariable(BoundVar var, LocalVariable localVariable) {
132 localVariables.put(var, localVariable);
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();
143 localVariable = createLocalVariable(null, typeDesc);
144 localVariables.put(var, localVariable);
146 return localVariable;
149 public void jump(ContRef target) {
150 jump(target.getBinding());
153 public void jump(ContRef target, Val ... parameters) {
154 jump(target.getBinding(), parameters);
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));
163 block.generateCode(this);
166 throw new InternalCompilerError();
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()));
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);
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));
197 block.generateCode(this);
200 throw new InternalCompilerError();
203 public void store(BoundVar var) {
204 Type type = var.getType();
205 TypeDesc typeDesc = getJavaTypeTranslator().toTypeDesc(type);
206 if(typeDesc.equals(TypeDesc.VOID))
208 LocalVariable lv = getLocalVariable(var);
213 * Generates the continuation code if it does not already exist.
215 public void ensureExists(Cont continuation) {
216 if(!generatedConts.contains(continuation))
217 ((SSABlock)continuation).generateCode(this);
220 @SuppressWarnings("unchecked")
221 public <T> T getPreparation(PreparationStep<T> step) {
222 return (T)preparationSteps.get(step);
225 public <T> void addPreparation(PreparationStep<T> step, T result) {
226 preparationSteps.put(step, result);
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);
235 else if(val instanceof LocalVariableConstant) {
236 return ((LocalVariableConstant)val).var;
239 LocalVariable temp = createLocalVariable(null, getJavaTypeTranslator().toTypeDesc(type));