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.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;
20 import gnu.trove.map.hash.THashMap;
21 import gnu.trove.set.hash.THashSet;
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);
30 public MethodBuilder(ClassBuilder classBuilder, ModuleBuilder moduleBuilder, boolean isStatic, MethodVisitor methodVisitor, TypeDesc[] parameterTypes) {
31 super(classBuilder, isStatic, methodVisitor, parameterTypes);
32 this.moduleBuilder = moduleBuilder;
35 public JavaTypeTranslator getJavaTypeTranslator() {
36 return getModuleBuilder().getJavaTypeTranslator();
39 public ModuleBuilder getModuleBuilder() {
43 public void push(IVal val, Type type) {
45 if(Types.canonical(type) instanceof TVar)
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]);
55 public void pushBoxed(Val val) {
60 public void pushBoxed(Val[] vals) {
65 public void genericApply(int arity) {
66 invokeInterface(Constants.FUNCTION, "apply", TypeDesc.OBJECT, Constants.OBJECTS[arity]);
69 public void pushTuple0() {
70 loadStaticField(Constants.TUPLE0, "INSTANCE", Constants.TUPLE0);
73 private void boxPrimitiveType(TypeDesc primitiveType) {
74 if(primitiveType.equals(TypeDesc.VOID)) {
78 TypeDesc objectType = primitiveType.toObjectType();
79 invokeStatic(getClassName(objectType), "valueOf",
80 objectType, new TypeDesc[] {primitiveType});
85 * Boxes the top of the stack.
87 public void box(Type type) {
88 TypeDesc typeDesc = getJavaTypeTranslator().toTypeDesc(type);
89 if(typeDesc.isPrimitive()) {
90 boxPrimitiveType(typeDesc);
92 //codeBuilder.convert(typeDesc, TypeDesc.OBJECT);
96 * Unboxes the top of the stack.
98 public void unbox(Type type) {
99 TypeDesc td = getJavaTypeTranslator().toTypeDesc(type);
100 if(td.equals(TypeDesc.VOID)) {
104 if(td.isPrimitive()) {
105 TypeDesc objectType = td.toObjectType();
106 checkCast(objectType);
107 convert(objectType, td);
110 if(td != TypeDesc.OBJECT)
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");
121 public Label getLabel(Cont continuation) {
122 Label label = labels.get(continuation);
124 label = createLabel();
125 labels.put(continuation, label);
130 public void setLocalVariable(BoundVar var, LocalVariable localVariable) {
131 localVariables.put(var, localVariable);
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();
142 localVariable = createLocalVariable(null, typeDesc);
143 localVariables.put(var, localVariable);
145 return localVariable;
148 public void jump(ContRef target) {
149 jump(target.getBinding());
152 public void jump(ContRef target, Val ... parameters) {
153 jump(target.getBinding(), parameters);
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));
162 block.generateCode(this);
165 throw new InternalCompilerError();
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()));
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);
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));
196 block.generateCode(this);
199 throw new InternalCompilerError();
202 public void store(BoundVar var) {
203 Type type = var.getType();
204 TypeDesc typeDesc = getJavaTypeTranslator().toTypeDesc(type);
205 if(typeDesc.equals(TypeDesc.VOID))
207 LocalVariable lv = getLocalVariable(var);
212 * Generates the continuation code if it does not already exist.
214 public void ensureExists(Cont continuation) {
215 if(!generatedConts.contains(continuation))
216 ((SSABlock)continuation).generateCode(this);
219 @SuppressWarnings("unchecked")
220 public <T> T getPreparation(PreparationStep<T> step) {
221 return (T)preparationSteps.get(step);
224 public <T> void addPreparation(PreparationStep<T> step, T result) {
225 preparationSteps.put(step, result);
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);
235 LocalVariable temp = createLocalVariable(null, getJavaTypeTranslator().toTypeDesc(type));