Ejemplo n.º 1
0
 public ClosureEnvironment(IEnumerable <Symbol> capturedVariables, bool isStruct)
 {
     CapturedVariables = new SetWithInsertionOrder <Symbol>();
     foreach (var item in capturedVariables)
     {
         CapturedVariables.Add(item);
     }
     IsStruct = isStruct;
 }
Ejemplo n.º 2
0
            private void MakeAndAssignEnvironments()
            {
                VisitScopeTree(ScopeTree, scope =>
                {
                    // Currently all variables declared in the same scope are added
                    // to the same closure environment
                    var variablesInEnvironment = scope.DeclaredVariables;

                    // Don't create empty environments
                    if (variablesInEnvironment.Count == 0)
                    {
                        return;
                    }

                    // First walk the nested scopes to find all closures which
                    // capture variables from this scope. They all need to capture
                    // this environment. This includes closures which captured local
                    // functions that capture those variables, so multiple passes may
                    // be needed. This will also decide if the environment is a struct
                    // or a class.
                    bool isStruct = true;
                    var closures  = new SetWithInsertionOrder <Closure>();
                    bool addedItem;

                    // This loop is O(n), where n is the length of the chain
                    //   L_1 <- L_2 <- L_3 ...
                    // where L_1 represents a local function that directly captures the current
                    // environment, L_2 represents a local function that directly captures L_1,
                    // L_3 represents a local function that captures L_2, and so on.
                    //
                    // Each iteration of the loop runs a visitor that is proportional to the
                    // number of closures in nested scopes, so we hope that the total number
                    // of nested functions and function chains is small in any real-world code.
                    do
                    {
                        addedItem = false;
                        VisitClosures(scope, (closureScope, closure) =>
                        {
                            if (!closures.Contains(closure) &&
                                (closure.CapturedVariables.Overlaps(scope.DeclaredVariables) ||
                                 closure.CapturedVariables.Overlaps(closures.Select(c => c.OriginalMethodSymbol))))
                            {
                                closures.Add(closure);
                                addedItem = true;
                                isStruct &= CanTakeRefParameters(closure.OriginalMethodSymbol);
                            }
                        });
                    } while (addedItem == true);

                    // Next create the environment and add it to the declaration scope
                    var env = new ClosureEnvironment(variablesInEnvironment, isStruct);
                    scope.DeclaredEnvironments.Add(env);

                    _topLevelMethod.TryGetThisParameter(out var thisParam);
                    foreach (var closure in closures)
                    {
                        closure.CapturedEnvironments.Add(env);
                        if (thisParam != null && env.CapturedVariables.Contains(thisParam))
                        {
                            closure.CapturesThis = true;
                        }
                    }
                });
            }
Ejemplo n.º 3
0
            private void MakeAndAssignEnvironments(ArrayBuilder <ClosureDebugInfo> closureDebugInfo)
            {
                VisitScopeTree(ScopeTree, scope =>
                {
                    if (scope.DeclaredVariables.Count > 0)
                    {
                        // First walk the nested scopes to find all closures which
                        // capture variables from this scope. They all need to capture
                        // this environment. This includes closures which captured local
                        // functions that capture those variables, so multiple passes may
                        // be needed. This will also decide if the environment is a struct
                        // or a class.
                        bool isStruct = true;
                        var closures  = new SetWithInsertionOrder <Closure>();
                        bool addedItem;
                        do
                        {
                            addedItem = false;
                            VisitClosures(scope, (closureScope, closure) =>
                            {
                                if (!closures.Contains(closure) &&
                                    (closure.CapturedVariables.Overlaps(scope.DeclaredVariables) ||
                                     closure.CapturedVariables.Overlaps(closures.Select(c => c.OriginalMethodSymbol))))
                                {
                                    closures.Add(closure);
                                    addedItem = true;
                                    isStruct &= CanTakeRefParameters(closure.OriginalMethodSymbol);
                                }
                            });
                        } while (addedItem == true);

                        // Next create the environment and add it to the declaration scope
                        // Currently all variables declared in the same scope are added
                        // to the same closure environment
                        var env = MakeEnvironment(scope, scope.DeclaredVariables, isStruct);
                        scope.DeclaredEnvironments.Add(env);

                        foreach (var closure in closures)
                        {
                            closure.CapturedEnvironments.Add(env);
                        }
                    }
                });

                ClosureEnvironment MakeEnvironment(Scope scope, IEnumerable <Symbol> capturedVariables, bool isStruct)
                {
                    var scopeBoundNode = scope.BoundNode;

                    var syntax = scopeBoundNode.Syntax;

                    Debug.Assert(syntax != null);

                    DebugId methodId  = GetTopLevelMethodId();
                    DebugId closureId = GetClosureId(syntax, closureDebugInfo);

                    var containingMethod = scope.ContainingClosureOpt?.OriginalMethodSymbol ?? _topLevelMethod;

                    if ((object)_substitutedSourceMethod != null && containingMethod == _topLevelMethod)
                    {
                        containingMethod = _substitutedSourceMethod;
                    }

                    return(new ClosureEnvironment(
                               capturedVariables,
                               _topLevelMethod,
                               containingMethod,
                               isStruct,
                               syntax,
                               methodId,
                               closureId));
                }
            }