]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/ssa/statements/LetFunctions.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 / statements / LetFunctions.java
index ee5dcc7148533bfcaf8a8e44ee7d426b794ce1ca..dc6a8580d713cc8c579ef1cbdfb45aad24dd34ea 100644 (file)
-package org.simantics.scl.compiler.internal.codegen.ssa.statements;\r
-\r
-import java.util.ArrayList;\r
-\r
-import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;\r
-import org.simantics.scl.compiler.constants.Constant;\r
-import org.simantics.scl.compiler.constants.SCLConstant;\r
-import org.simantics.scl.compiler.internal.codegen.references.BoundVar;\r
-import org.simantics.scl.compiler.internal.codegen.references.ValRef;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.SSAClosure;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.SSAStatement;\r
-import org.simantics.scl.compiler.internal.codegen.ssa.binders.ClosureBinder;\r
-import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;\r
-import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;\r
-import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;\r
-import org.simantics.scl.compiler.internal.codegen.utils.SSALambdaLiftingContext;\r
-import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;\r
-import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;\r
-import org.simantics.scl.compiler.internal.codegen.utils.ValRefVisitor;\r
-import org.simantics.scl.compiler.types.TVar;\r
-import org.simantics.scl.compiler.types.Type;\r
-import org.simantics.scl.compiler.types.Types;\r
-\r
-import gnu.trove.map.hash.THashMap;\r
-import gnu.trove.set.hash.THashSet;\r
-\r
-public class LetFunctions extends SSAStatement implements ClosureBinder {\r
-    long recursiveGroupLocation;\r
-    SSAClosure firstClosure;\r
-\r
-    public LetFunctions() {\r
-    }\r
-    \r
-    public LetFunctions(SSAClosure closure) {\r
-        firstClosure = closure;\r
-        closure.setParent(this);\r
-    }\r
-\r
-    @Override\r
-    public void toString(PrintingContext context) {\r
-        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {\r
-            context.indentation();\r
-            context.append(closure.getTarget());\r
-            context.append("(" + closure.getTarget().occurrenceCount() + ")");\r
-            context.append(" :: ");\r
-            context.append(closure.getTarget().getType());\r
-            context.append(" = \n");\r
-            context.indent();\r
-            closure.toString(context);\r
-            context.dedent();\r
-        }\r
-    }\r
-    \r
-    public void addClosure(SSAClosure closure) {\r
-        closure.setParent(this);        \r
-        closure.setNext(firstClosure);\r
-        if(firstClosure != null)\r
-            firstClosure.setPrev(closure);\r
-        firstClosure = closure;\r
-    }\r
-\r
-    @Override\r
-    public void generateCode(MethodBuilder mb) {\r
-        throw new InternalCompilerError("Functions should be lambda lifted before code generation");        \r
-    }\r
-\r
-    @Override\r
-    public void validate(SSAValidationContext context) {\r
-        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {\r
-            if(!(closure.getTarget() instanceof BoundVar))\r
-                throw new InternalCompilerError();\r
-            closure.validate(context);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void destroy() {\r
-        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())\r
-            closure.destroy();\r
-    }\r
-\r
-    @Override\r
-    public SSAStatement copy(CopyContext context) {\r
-        LetFunctions result = new LetFunctions();\r
-        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {\r
-            SSAClosure newFunction = closure.copy(context);\r
-            newFunction.setTarget(context.copy(closure.getTarget()));\r
-            result.addClosure(newFunction);\r
-        }\r
-        return result;        \r
-    }\r
-\r
-    @Override\r
-    public void replace(TVar[] vars, Type[] replacements) {\r
-        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {\r
-            ((BoundVar)closure.getTarget()).replace(vars, replacements);\r
-            closure.replace(vars, replacements);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void addBoundVariablesTo(SSAValidationContext context) {\r
-        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())\r
-            context.validBoundVariables.add((BoundVar)closure.getTarget());        \r
-    }\r
-\r
-    @Override\r
-    public SSAClosure getFirstClosure() {\r
-        return firstClosure;\r
-    }\r
-\r
-    @Override\r
-    public void setFirstClosure(SSAClosure function) {\r
-        this.firstClosure = function;     \r
-        if(function == null)\r
-            detach();\r
-    }\r
-\r
-    @Override\r
-    public void collectFreeVariables(SSAFunction parentFunction,\r
-            ArrayList<ValRef> vars) {\r
-        throw new InternalCompilerError("Should not be called for non-lambda-lifted functions.");\r
-        // FIXME inefficient, some kind of caching needed here\r
-        /*THashSet<BoundVar> tempVars = new THashSet<BoundVar>();\r
-        for(SSAFunction function = firstFunction; function != null; function = function.getNext())\r
-            function.collectFreeVariables(tempVars);\r
-        \r
-        for(BoundVar var : tempVars)\r
-            if(var.getFunctionParent() != parentFunction)\r
-                vars.add(var);*/\r
-    }\r
-\r
-    @Override\r
-    public void lambdaLift(SSALambdaLiftingContext context) {\r
-        boolean hasValues = false;\r
-        boolean isRecursive = false;\r
-        \r
-        // Lambda lift substructure and collect free variables\r
-        THashSet<BoundVar> targets = new THashSet<BoundVar>();\r
-        ArrayList<ValRef> freeVars = new ArrayList<ValRef>();        \r
-        for(SSAClosure closure = firstClosure; \r
-                closure != null; \r
-                closure = closure.getNext()) {\r
-            hasValues |= closure.isValue();\r
-            closure.lambdaLift(context);\r
-            targets.add((BoundVar)closure.getTarget());\r
-            closure.collectFreeVariables(freeVars);\r
-        }\r
-        \r
-        if(!(firstClosure instanceof SSAFunction) && firstClosure.getNext() == null) {\r
-            THashMap<BoundVar, BoundVar> varMap = new THashMap<BoundVar, BoundVar>(); \r
-            ArrayList<BoundVar> oldVarsList = new ArrayList<BoundVar>(4);\r
-            ArrayList<BoundVar> newVarsList = new ArrayList<BoundVar>(4);\r
-            BoundVar newTarget = null;\r
-            for(ValRef ref : freeVars) {\r
-                BoundVar var = (BoundVar)ref.getBinding();\r
-                if(targets.contains(var)) {\r
-                    if(newTarget == null)\r
-                        newTarget = new BoundVar(var.getType());\r
-                    ref.replaceBy(newTarget);\r
-                    continue;\r
-                }\r
-                BoundVar newVar = varMap.get(var);\r
-                if(newVar == null) {\r
-                    newVar = new BoundVar(var.getType());\r
-                    oldVarsList.add(var);\r
-                    newVarsList.add(newVar);\r
-                    varMap.put(var, newVar);\r
-                }\r
-                ref.replaceBy(newVar);\r
-            }\r
-            Constant constant = firstClosure.liftClosure(newTarget, newVarsList.toArray(new BoundVar[newVarsList.size()]));\r
-            new LetApply(targets.iterator().next(), Types.PROC, constant.createOccurrence(), ValRef.createOccurrences(oldVarsList))\r
-            .insertBefore(this);\r
-            detach();\r
-            context.addClosure(firstClosure);\r
-            return;\r
-        }\r
-                \r
-        // Classify by BoundVars\r
-        THashSet<BoundVar> boundVars = new THashSet<BoundVar>(); \r
-        ArrayList<BoundVar> boundVarsList = new ArrayList<BoundVar>(4);\r
-        ArrayList<ValRef> newFreeVars = new ArrayList<ValRef>(freeVars.size()); \r
-        for(ValRef ref : freeVars) {\r
-            BoundVar var = (BoundVar)ref.getBinding();\r
-            if(targets.contains(var)) {\r
-                isRecursive = true;\r
-                continue;\r
-            }\r
-            if(boundVars.add(var))\r
-                boundVarsList.add(var);\r
-            newFreeVars.add(ref);\r
-        }\r
-        BoundVar[] outVars = boundVarsList.toArray(new BoundVar[boundVarsList.size()]);\r
-        freeVars = newFreeVars;\r
-        \r
-        // Modify functions\r
-        THashMap<SSAClosure, THashMap<BoundVar, BoundVar>> varMap = new THashMap<SSAClosure, THashMap<BoundVar, BoundVar>>();\r
-        THashMap<SSAClosure, BoundVar[]> inVarsMap = new THashMap<SSAClosure, BoundVar[]>();\r
-        THashMap<SSAClosure, BoundVar> oldTargets = new THashMap<SSAClosure, BoundVar>();\r
-        for(SSAClosure closure = firstClosure; \r
-                closure != null; \r
-                closure = closure.getNext()) {\r
-            THashMap<BoundVar, BoundVar> map = new THashMap<BoundVar, BoundVar>(outVars.length);\r
-            BoundVar[] inVars = new BoundVar[outVars.length];            \r
-            for(int i=0;i<inVars.length;++i) {\r
-                inVars[i] = new BoundVar(outVars[i].getType());\r
-                map.put(outVars[i], inVars[i]);\r
-            }\r
-            inVarsMap.put(closure, inVars);\r
-            varMap.put(closure, map);\r
-            \r
-            closure.parametrize(inVars);            \r
-            SCLConstant functionConstant = new SCLConstant(context.createName(), closure.getType());\r
-            context.addConstant(functionConstant);   \r
-            oldTargets.put(closure, (BoundVar)closure.getTarget());\r
-            closure.setTarget(functionConstant);\r
-            functionConstant.setDefinition((SSAFunction)closure);   \r
-            functionConstant.setPrivate(true);\r
-            // TODO handle type parameters\r
-            \r
-            // Define target by an application\r
-            /*new LetApply(oldTarget, functionConstant.createOccurrence(), \r
-                    ValRef.createOccurrences(outVars)).insertBefore(this);*/\r
-        }\r
-        \r
-        for(SSAClosure closure = firstClosure; \r
-                closure != null; \r
-                closure = closure.getNext()) {\r
-            BoundVar oldTarget = oldTargets.get(closure);\r
-            for(ValRef ref : oldTarget.getOccurences()) {\r
-                SSAFunction parent = ref.getParentFunction();\r
-                BoundVar[] vars = inVarsMap.get(parent);\r
-                if(vars == null)\r
-                    vars = outVars;\r
-                if(vars.length > 0)\r
-                    ref.replaceByApply(closure.getTarget(), vars);\r
-                else\r
-                    ref.replaceBy(closure.getTarget());\r
-            }\r
-        }\r
-            \r
-        // Fix references\r
-        for(ValRef ref : freeVars) {\r
-            BoundVar inVar = (BoundVar)ref.getBinding();\r
-            if(targets.contains(inVar))\r
-                continue;\r
-            BoundVar outVar = varMap.get(ref.getParentFunction()).get(inVar);\r
-            ref.replaceBy(outVar);\r
-        }\r
-        \r
-        detach();\r
-        //context.validate();\r
-        \r
-        if(hasValues && isRecursive)\r
-            context.getErrorLog().log(recursiveGroupLocation, "Variables defined recursively must all be functions.");\r
-    }\r
-    \r
-    @Override\r
-    public void simplify(SSASimplificationContext context) {\r
-        for(SSAClosure function = firstClosure; \r
-                function != null; \r
-                function = function.getNext())\r
-            function.simplify(context);\r
-    }\r
-    \r
-    public void setRecursiveGroupLocation(long recursiveGroupLocation) {\r
-        this.recursiveGroupLocation = recursiveGroupLocation;\r
-    }\r
-    \r
-    @Override\r
-    public void forValRefs(ValRefVisitor visitor) {\r
-        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())\r
-            closure.forValRefs(visitor);    \r
-    }\r
-}\r
+package org.simantics.scl.compiler.internal.codegen.ssa.statements;
+
+import java.util.ArrayList;
+
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.constants.Constant;
+import org.simantics.scl.compiler.constants.SCLConstant;
+import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
+import org.simantics.scl.compiler.internal.codegen.references.ValRef;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAClosure;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
+import org.simantics.scl.compiler.internal.codegen.ssa.SSAStatement;
+import org.simantics.scl.compiler.internal.codegen.ssa.binders.ClosureBinder;
+import org.simantics.scl.compiler.internal.codegen.utils.CopyContext;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
+import org.simantics.scl.compiler.internal.codegen.utils.PrintingContext;
+import org.simantics.scl.compiler.internal.codegen.utils.SSALambdaLiftingContext;
+import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext;
+import org.simantics.scl.compiler.internal.codegen.utils.SSAValidationContext;
+import org.simantics.scl.compiler.internal.codegen.utils.ValRefVisitor;
+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 LetFunctions extends SSAStatement implements ClosureBinder {
+    long recursiveGroupLocation;
+    SSAClosure firstClosure;
+
+    public LetFunctions() {
+    }
+    
+    public LetFunctions(SSAClosure closure) {
+        firstClosure = closure;
+        closure.setParent(this);
+    }
+
+    @Override
+    public void toString(PrintingContext context) {
+        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {
+            context.indentation();
+            context.append(closure.getTarget());
+            context.append("(" + closure.getTarget().occurrenceCount() + ")");
+            context.append(" :: ");
+            context.append(closure.getTarget().getType());
+            context.append(" = \n");
+            context.indent();
+            closure.toString(context);
+            context.dedent();
+        }
+    }
+    
+    public void addClosure(SSAClosure closure) {
+        closure.setParent(this);        
+        closure.setNext(firstClosure);
+        if(firstClosure != null)
+            firstClosure.setPrev(closure);
+        firstClosure = closure;
+    }
+
+    @Override
+    public void generateCode(MethodBuilder mb) {
+        throw new InternalCompilerError("Functions should be lambda lifted before code generation");        
+    }
+
+    @Override
+    public void validate(SSAValidationContext context) {
+        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {
+            if(!(closure.getTarget() instanceof BoundVar))
+                throw new InternalCompilerError();
+            closure.validate(context);
+        }
+    }
+
+    @Override
+    public void destroy() {
+        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())
+            closure.destroy();
+    }
+
+    @Override
+    public SSAStatement copy(CopyContext context) {
+        LetFunctions result = new LetFunctions();
+        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {
+            SSAClosure newFunction = closure.copy(context);
+            newFunction.setTarget(context.copy(closure.getTarget()));
+            result.addClosure(newFunction);
+        }
+        return result;        
+    }
+
+    @Override
+    public void replace(TVar[] vars, Type[] replacements) {
+        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext()) {
+            ((BoundVar)closure.getTarget()).replace(vars, replacements);
+            closure.replace(vars, replacements);
+        }
+    }
+
+    @Override
+    public void addBoundVariablesTo(SSAValidationContext context) {
+        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())
+            context.validBoundVariables.add((BoundVar)closure.getTarget());        
+    }
+
+    @Override
+    public SSAClosure getFirstClosure() {
+        return firstClosure;
+    }
+
+    @Override
+    public void setFirstClosure(SSAClosure function) {
+        this.firstClosure = function;     
+        if(function == null)
+            detach();
+    }
+
+    @Override
+    public void collectFreeVariables(SSAFunction parentFunction,
+            ArrayList<ValRef> vars) {
+        throw new InternalCompilerError("Should not be called for non-lambda-lifted functions.");
+        // FIXME inefficient, some kind of caching needed here
+        /*THashSet<BoundVar> tempVars = new THashSet<BoundVar>();
+        for(SSAFunction function = firstFunction; function != null; function = function.getNext())
+            function.collectFreeVariables(tempVars);
+        
+        for(BoundVar var : tempVars)
+            if(var.getFunctionParent() != parentFunction)
+                vars.add(var);*/
+    }
+
+    @Override
+    public void lambdaLift(SSALambdaLiftingContext context) {
+        boolean hasValues = false;
+        boolean isRecursive = false;
+        
+        // Lambda lift substructure and collect free variables
+        THashSet<BoundVar> targets = new THashSet<BoundVar>();
+        ArrayList<ValRef> freeVars = new ArrayList<ValRef>();        
+        for(SSAClosure closure = firstClosure; 
+                closure != null; 
+                closure = closure.getNext()) {
+            hasValues |= closure.isValue();
+            closure.lambdaLift(context);
+            targets.add((BoundVar)closure.getTarget());
+            closure.collectFreeVariables(freeVars);
+        }
+        
+        if(!(firstClosure instanceof SSAFunction) && firstClosure.getNext() == null) {
+            THashMap<BoundVar, BoundVar> varMap = new THashMap<BoundVar, BoundVar>(); 
+            ArrayList<BoundVar> oldVarsList = new ArrayList<BoundVar>(4);
+            ArrayList<BoundVar> newVarsList = new ArrayList<BoundVar>(4);
+            BoundVar newTarget = null;
+            for(ValRef ref : freeVars) {
+                BoundVar var = (BoundVar)ref.getBinding();
+                if(targets.contains(var)) {
+                    if(newTarget == null)
+                        newTarget = new BoundVar(var.getType());
+                    ref.replaceBy(newTarget);
+                    continue;
+                }
+                BoundVar newVar = varMap.get(var);
+                if(newVar == null) {
+                    newVar = new BoundVar(var.getType());
+                    newVar.setLabel(var.getLabel());
+                    oldVarsList.add(var);
+                    newVarsList.add(newVar);
+                    varMap.put(var, newVar);
+                }
+                ref.replaceBy(newVar);
+            }
+            Constant constant = firstClosure.liftClosure(newTarget, newVarsList.toArray(new BoundVar[newVarsList.size()]));
+            new LetApply(targets.iterator().next(), Types.PROC, constant.createOccurrence(), ValRef.createOccurrences(oldVarsList))
+            .insertBefore(this);
+            detach();
+            context.addClosure(firstClosure);
+            return;
+        }
+                
+        // Classify by BoundVars
+        THashSet<BoundVar> boundVars = new THashSet<BoundVar>(); 
+        ArrayList<BoundVar> boundVarsList = new ArrayList<BoundVar>(4);
+        ArrayList<ValRef> newFreeVars = new ArrayList<ValRef>(freeVars.size()); 
+        for(ValRef ref : freeVars) {
+            BoundVar var = (BoundVar)ref.getBinding();
+            if(targets.contains(var)) {
+                isRecursive = true;
+                continue;
+            }
+            if(boundVars.add(var))
+                boundVarsList.add(var);
+            newFreeVars.add(ref);
+        }
+        BoundVar[] outVars = boundVarsList.toArray(new BoundVar[boundVarsList.size()]);
+        freeVars = newFreeVars;
+        
+        // Modify functions
+        THashMap<SSAClosure, THashMap<BoundVar, BoundVar>> varMap = new THashMap<SSAClosure, THashMap<BoundVar, BoundVar>>();
+        THashMap<SSAClosure, BoundVar[]> inVarsMap = new THashMap<SSAClosure, BoundVar[]>();
+        THashMap<SSAClosure, BoundVar> oldTargets = new THashMap<SSAClosure, BoundVar>();
+        for(SSAClosure closure = firstClosure; 
+                closure != null; 
+                closure = closure.getNext()) {
+            THashMap<BoundVar, BoundVar> map = new THashMap<BoundVar, BoundVar>(outVars.length);
+            BoundVar[] inVars = new BoundVar[outVars.length];            
+            for(int i=0;i<inVars.length;++i) {
+                inVars[i] = new BoundVar(outVars[i].getType());
+                map.put(outVars[i], inVars[i]);
+            }
+            inVarsMap.put(closure, inVars);
+            varMap.put(closure, map);
+            
+            closure.parametrize(inVars);
+            SCLConstant functionConstant = new SCLConstant(context.createName(), closure.getType());
+            context.addConstant(functionConstant);   
+            oldTargets.put(closure, (BoundVar)closure.getTarget());
+            closure.setTarget(functionConstant);
+            functionConstant.setDefinition((SSAFunction)closure);   
+            functionConstant.setPrivate(true);
+            // TODO handle type parameters
+            
+            // Define target by an application
+            /*new LetApply(oldTarget, functionConstant.createOccurrence(), 
+                    ValRef.createOccurrences(outVars)).insertBefore(this);*/
+        }
+        
+        for(SSAClosure closure = firstClosure; 
+                closure != null; 
+                closure = closure.getNext()) {
+            BoundVar oldTarget = oldTargets.get(closure);
+            for(ValRef ref : oldTarget.getOccurences()) {
+                SSAFunction parent = ref.getParentFunction();
+                BoundVar[] vars = inVarsMap.get(parent);
+                if(vars == null)
+                    vars = outVars;
+                if(vars.length > 0)
+                    ref.replaceByApply(closure.getTarget(), vars);
+                else
+                    ref.replaceBy(closure.getTarget());
+            }
+        }
+            
+        // Fix references
+        for(ValRef ref : freeVars) {
+            BoundVar inVar = (BoundVar)ref.getBinding();
+            if(targets.contains(inVar))
+                continue;
+            BoundVar outVar = varMap.get(ref.getParentFunction()).get(inVar);
+            ref.replaceBy(outVar);
+        }
+        
+        detach();
+        //context.validate();
+        
+        if(hasValues && isRecursive)
+            context.getErrorLog().log(recursiveGroupLocation, "Variables defined recursively must all be functions.");
+    }
+    
+    @Override
+    public void simplify(SSASimplificationContext context) {
+        for(SSAClosure function = firstClosure; 
+                function != null; 
+                function = function.getNext())
+            function.simplify(context);
+    }
+    
+    public void setRecursiveGroupLocation(long recursiveGroupLocation) {
+        this.recursiveGroupLocation = recursiveGroupLocation;
+    }
+    
+    @Override
+    public void forValRefs(ValRefVisitor visitor) {
+        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())
+            closure.forValRefs(visitor);    
+    }
+
+    @Override
+    public void cleanup() {
+        for(SSAClosure closure = firstClosure; closure != null; closure = closure.getNext())
+            closure.cleanup();
+    }
+}