--- /dev/null
+package org.simantics.scl.compiler.internal.codegen.utils;
+
+import org.cojen.classfile.TypeDesc;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
+import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;
+import org.simantics.scl.compiler.internal.codegen.continuations.ReturnCont;
+import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
+import org.simantics.scl.compiler.internal.codegen.references.IVal;
+import org.simantics.scl.compiler.internal.codegen.references.Val;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock;
+import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
+import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
+import org.simantics.scl.compiler.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.set.hash.THashSet;
+
+public class MethodBuilder extends MethodBuilderBase {
+ ModuleBuilder moduleBuilder;
+ THashMap<Cont, Label> labels = new THashMap<Cont, Label>();
+ THashMap<BoundVar, LocalVariable> localVariables = new THashMap<BoundVar, LocalVariable>();
+ THashSet<Cont> generatedConts = new THashSet<Cont>();
+ THashMap<Object,Object> preparationSteps = new THashMap<Object,Object>(4);
+
+ public MethodBuilder(ClassBuilder classBuilder, ModuleBuilder moduleBuilder, boolean isStatic, MethodVisitor methodVisitor, TypeDesc[] parameterTypes) {
+ super(classBuilder, isStatic, methodVisitor, parameterTypes);
+ this.moduleBuilder = moduleBuilder;
+ }
+
+ public JavaTypeTranslator getJavaTypeTranslator() {
+ return getModuleBuilder().getJavaTypeTranslator();
+ }
+
+ public ModuleBuilder getModuleBuilder() {
+ return moduleBuilder;
+ }
+
+ public void push(IVal val, Type type) {
+ val.push(this);
+ if(Types.canonical(type) instanceof TVar)
+ box(val.getType());
+ }
+
+ public void push(Val[] vals, Type[] types) {
+ assert(vals.length == types.length);
+ for(int i=0;i<vals.length;++i)
+ push(vals[i], types[i]);
+ }
+
+ public void pushBoxed(Val val) {
+ val.push(this);
+ box(val.getType());
+ }
+
+ public void pushBoxed(Val[] vals) {
+ for(Val val : vals)
+ pushBoxed(val);
+ }
+
+ public void genericApply(int arity) {
+ invokeInterface(Constants.FUNCTION, "apply", TypeDesc.OBJECT, Constants.OBJECTS[arity]);
+ }
+
+ public void pushTuple0() {
+ loadStaticField(Constants.TUPLE0, "INSTANCE", Constants.TUPLE0);
+ }
+
+ private void boxPrimitiveType(TypeDesc primitiveType) {
+ if(primitiveType.equals(TypeDesc.VOID)) {
+ pushTuple0();
+ }
+ else {
+ TypeDesc objectType = primitiveType.toObjectType();
+ invokeStatic(getClassName(objectType), "valueOf",
+ objectType, new TypeDesc[] {primitiveType});
+ }
+ }
+
+ /**
+ * Boxes the top of the stack.
+ */
+ public void box(Type type) {
+ TypeDesc typeDesc = getJavaTypeTranslator().toTypeDesc(type);
+ if(typeDesc.isPrimitive()) {
+ boxPrimitiveType(typeDesc);
+ }
+ //codeBuilder.convert(typeDesc, TypeDesc.OBJECT);
+ }
+
+ /**
+ * Unboxes the top of the stack.
+ */
+ public void unbox(Type type) {
+ TypeDesc td = getJavaTypeTranslator().toTypeDesc(type);
+ if(td.equals(TypeDesc.VOID)) {
+ pop();
+ return;
+ }
+ if(td.isPrimitive()) {
+ TypeDesc objectType = td.toObjectType();
+ checkCast(objectType);
+ convert(objectType, td);
+ }
+ else {
+ if(td != TypeDesc.OBJECT)
+ checkCast(td);
+ }
+ }
+
+ public void setLocation(Cont continuation) {
+ setLocation(getLabel(continuation));
+ if(!generatedConts.add(continuation))
+ throw new InternalCompilerError("Label location is set multiple times");
+ }
+
+ public Label getLabel(Cont continuation) {
+ Label label = labels.get(continuation);
+ if(label == null) {
+ label = createLabel();
+ labels.put(continuation, label);
+ }
+ return label;
+ }
+
+ public void setLocalVariable(BoundVar var, LocalVariable localVariable) {
+ localVariables.put(var, localVariable);
+ }
+
+ public LocalVariable getLocalVariable(BoundVar var) {
+ LocalVariable localVariable = localVariables.get(var);
+ if(localVariable == null) {
+ TypeDesc typeDesc = getJavaTypeTranslator().getTypeDesc(var);
+ if(SCLCompilerConfiguration.DEBUG) {
+ if(typeDesc.equals(TypeDesc.VOID))
+ throw new InternalCompilerError();
+ }
+ localVariable = createLocalVariable(null, typeDesc);
+ localVariables.put(var, localVariable);
+ }
+ return localVariable;
+ }
+
+ public void jump(ContRef target) {
+ jump(target.getBinding());
+ }
+
+ public void jump(ContRef target, Val ... parameters) {
+ jump(target.getBinding(), parameters);
+ }
+
+ public void jump(Cont cont) {
+ if(cont instanceof SSABlock) {
+ SSABlock block = (SSABlock)cont;
+ if(generatedConts.contains(block))
+ branch(getLabel(block));
+ else
+ block.generateCode(this);
+ }
+ else
+ throw new InternalCompilerError();
+ }
+
+ public void jump(Cont cont, IVal ... parameters) {
+ if(cont instanceof ReturnCont) {
+ ReturnCont returnCont = (ReturnCont)cont;
+ if(parameters.length != 1)
+ throw new InternalCompilerError();
+ push(parameters[0], returnCont.getType());
+ //parameters[0].push(this);
+ returnValue(getJavaTypeTranslator().toTypeDesc(returnCont.getType()));
+ }
+ else if(cont instanceof SSABlock) {
+ SSABlock block = (SSABlock)cont;
+ BoundVar[] parameterVars = block.getParameters();
+ if(parameters.length != parameterVars.length)
+ throw new InternalCompilerError();
+ // First calculate all parameters and push them into stack
+ for(int i=0;i<parameters.length;++i)
+ if(parameters[i] != parameterVars[i]) {
+ push(parameters[i], parameterVars[i].getType());
+ //parameters[i].push(this);
+ }
+ // Then store them to the local variables
+ // NOTE: some computations inside pushs may depend on these variables
+ for(int i=parameters.length-1;i>=0;--i)
+ if(parameters[i] != parameterVars[i])
+ store(parameterVars[i]);
+ if(generatedConts.contains(block))
+ branch(getLabel(block));
+ else
+ block.generateCode(this);
+ }
+ else
+ throw new InternalCompilerError();
+ }
+
+ public void store(BoundVar var) {
+ Type type = var.getType();
+ TypeDesc typeDesc = getJavaTypeTranslator().toTypeDesc(type);
+ if(typeDesc.equals(TypeDesc.VOID))
+ return;
+ LocalVariable lv = getLocalVariable(var);
+ storeLocal(lv);
+ }
+
+ public void ensureExists(Cont continuation) {
+ if(!generatedConts.contains(continuation))
+ ((SSABlock)continuation).generateCode(this);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T getPreparation(PreparationStep<T> step) {
+ return (T)preparationSteps.get(step);
+ }
+
+ public <T> void addPreparation(PreparationStep<T> step, T result) {
+ preparationSteps.put(step, result);
+ }
+}