]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/exits/If.java
Added memory leak test and fixed the leak by removing references
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / ssa / exits / If.java
1 package org.simantics.scl.compiler.internal.codegen.ssa.exits;
2
3 import java.util.ArrayList;
4
5 import org.objectweb.asm.Label;
6 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
7 import org.simantics.scl.compiler.constants.BooleanConstant;
8 import org.simantics.scl.compiler.constants.ComparisonFunction;
9 import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
10 import org.simantics.scl.compiler.internal.codegen.continuations.ContRef;
11 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
12 import org.simantics.scl.compiler.internal.codegen.references.Val;
13 import org.simantics.scl.compiler.internal.codegen.references.ValRef;
14 import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock;
15 import org.simantics.scl.compiler.internal.codegen.ssa.SSAExit;
16 import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
17 import org.simantics.scl.compiler.internal.codegen.ssa.binders.ValRefBinder;
18 import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply;
19 import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;
20 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
21 import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
22 import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
23 import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
24 import org.simantics.scl.compiler.internal.codegen.utils.ValRefVisitor;
25 import org.simantics.scl.compiler.types.TVar;
26 import org.simantics.scl.compiler.types.Type;
27 import org.simantics.scl.compiler.types.Types;
28
29 public class If extends SSAExit implements ValRefBinder {
30     private ValRef condition;
31     private ContRef thenTarget;
32     private ContRef elseTarget;
33     
34     public If(ValRef condition, ContRef thenTarget, ContRef elseTarget) {
35         setCondition(condition);
36         setThenTarget(thenTarget);
37         setElseTarget(elseTarget);
38     }
39     
40     public void setCondition(ValRef condition) {
41         this.condition = condition;
42         condition.setParent(this);
43     }
44     
45     public void setThenTarget(ContRef thenTarget) {
46         this.thenTarget = thenTarget;
47         thenTarget.setParent(this);
48     }
49     
50     public void setElseTarget(ContRef elseTarget) {
51         this.elseTarget = elseTarget;
52         elseTarget.setParent(this);
53     }
54
55     @Override
56     public void generateCode(MethodBuilder mb) {
57         Val binding = condition.getBinding();
58         simplifyTestCode: if(binding instanceof BoundVar) {
59             BoundVar boundVar = (BoundVar)binding;
60             if(!boundVar.generateOnFly)
61                 break simplifyTestCode;
62             LetApply apply = (LetApply)boundVar.getParent();
63             Val function = apply.getFunction().getBinding();
64             if(!(function instanceof ComparisonFunction))
65                 break simplifyTestCode;
66
67             Val[] ps = ValRef.getBindings(apply.getParameters());
68             ((ComparisonFunction)function).generateCondition(mb, ps, thenTarget.getBinding(), elseTarget.getBinding());
69             return;
70         }
71         mb.push(condition.getBinding(), Types.BOOLEAN);
72         Label elseLabel = mb.getLabel(elseTarget.getBinding());
73         mb.ifZeroComparisonBranch(elseLabel, "==");
74         mb.jump(thenTarget.getBinding());
75         mb.ensureExists(elseTarget.getBinding());
76     }
77
78     @Override
79     public void toString(PrintingContext context) {
80         context.append("if ");
81         context.append(condition);
82         context.append(" then ");
83         {
84             Cont thenCont = thenTarget.getBinding();
85             if(thenCont instanceof SSABlock) {
86                 SSABlock thenBlock = (SSABlock)thenCont;
87                 if(thenCont.hasMoreThanOneOccurences()) {
88                     context.append(thenCont);
89                     context.addBlock(thenBlock);
90                     context.append(' ');
91                 }
92                 else {
93                     context.append('\n');
94                     thenBlock.bodyToString(context);
95                     context.indentation();
96                 }
97             }
98             else {
99                 context.append(thenCont);
100                 context.append(' ');
101             }
102         }        
103         context.append("else ");
104         {
105             Cont elseCont = elseTarget.getBinding();
106             if(elseCont instanceof SSABlock) {
107                 SSABlock elseBlock = (SSABlock)elseCont;
108                 if(elseCont.hasMoreThanOneOccurences()) {
109                     context.append(elseCont);
110                     context.addBlock(elseBlock);
111                     context.append('\n');
112                 }
113                 else {
114                     context.append('\n');
115                     elseBlock.bodyToString(context);
116                 }
117             }
118             else {
119                 context.append(elseCont);
120                 context.append('\n');
121             }
122         }
123     }
124
125     @Override
126     public void validate(SSAValidationContext context) {
127         context.validate(condition);
128         context.validate(elseTarget);
129         context.validate(thenTarget);
130         if(condition.getParent() != this)
131             throw new InternalCompilerError();
132         if(elseTarget.getParent() != this)
133             throw new InternalCompilerError();
134         if(thenTarget.getParent() != this)
135             throw new InternalCompilerError();
136         context.assertEquals(this, condition.getType(), Types.BOOLEAN);
137         context.assertEquals(elseTarget.getBinding().getArity(), 0);
138         context.assertEquals(thenTarget.getBinding().getArity(), 0);
139     }
140
141     @Override
142     public void destroy() {
143         condition.remove();
144         elseTarget.remove();
145         thenTarget.remove();
146     }
147
148     @Override
149     public SSAExit copy(CopyContext context) {
150         return new If(context.copy(condition),
151                 context.copy(thenTarget),
152                 context.copy(elseTarget));
153     }
154     
155     @Override
156     public void replace(TVar[] vars, Type[] replacements) {
157         condition.replace(vars, replacements);        
158     }
159     
160     @Override
161     public void simplify(SSASimplificationContext context) {
162         Val cond = condition.getBinding();
163         if(cond instanceof BooleanConstant) {
164             SSAExit newExit;
165             if(((BooleanConstant) cond).getValue()) {
166                 newExit = new Jump(thenTarget);
167                 elseTarget.remove();
168             }
169             else {
170                 newExit = new Jump(elseTarget);
171                 thenTarget.remove();
172             }
173             condition.remove();
174             getParent().setExit(newExit);
175             context.markModified("beta-if");
176         }
177         else if(thenTarget.getBinding() == elseTarget.getBinding()) {
178             elseTarget.remove();
179             condition.remove();
180             getParent().setExit(new Jump(thenTarget));
181             context.markModified("equal-branches-if");
182         }
183     }
184
185     @Override
186     public void collectFreeVariables(SSAFunction function,
187             ArrayList<ValRef> vars) {
188         condition.collectFreeVariables(function, vars);
189     }
190     
191     @Override
192     public Cont addParametersInFrontOf(ContRef contRef, Val[] newParameters, Val[] oldParameters,
193             Cont proxy) {
194         if(proxy == null)
195             proxy = contRef.getBinding().createProxy(getParent().getParent(), newParameters, oldParameters);
196         ContRef proxyRef = proxy.createOccurrence();
197         if(thenTarget == contRef)
198             setThenTarget(proxyRef);
199         else
200             setElseTarget(proxyRef);
201         return proxy;
202     }
203
204     @Override
205     public SSABlock[] getSuccessors() {
206         Cont thenCont = thenTarget.getBinding();
207         Cont elseCont = elseTarget.getBinding();
208         if(thenCont instanceof SSABlock) {
209             if(elseCont instanceof SSABlock)
210                 return new SSABlock[] {(SSABlock)thenCont, (SSABlock)elseCont};
211             else
212                 return new SSABlock[] {(SSABlock)thenCont};
213         }
214         else {
215             if(elseCont instanceof SSABlock)
216                 return new SSABlock[] {(SSABlock)elseCont};
217             else
218                 return SSABlock.EMPTY_ARRAY;
219         }
220     }
221
222     @Override
223     public void forValRefs(ValRefVisitor visitor) {
224         visitor.visit(condition);
225     }
226
227     @Override
228     public void cleanup() {
229         condition.remove();
230     }
231 }