Beispiel #1
0
            public static IList <MethodSymbol> GetSelfStaticCalls(BoundBlock block)
            {
                var visitor = new LateStaticCallsLookup();

                visitor.Accept(block);
                return((IList <MethodSymbol>)visitor._lazyStaticCalls ?? Array.Empty <MethodSymbol>());
            }
Beispiel #2
0
        /// <summary>
        /// Walks static methods that don't use late static binding and checks if it should forward the late static type;
        /// hence it must know the late static as well.
        /// </summary>
        void ForwardLateStaticBindings()
        {
            var calls = new ConcurrentBag <KeyValuePair <SourceMethodSymbol, MethodSymbol> >();

            // collect self:: or parent:: static calls
            this.WalkMethods(routine =>
            {
                if (routine is SourceMethodSymbol caller && caller.IsStatic && (caller.Flags & RoutineFlags.UsesLateStatic) == 0)
                {
                    var cfg = caller.ControlFlowGraph;
                    if (cfg == null)
                    {
                        return;
                    }

                    // has self:: or parent:: call to a routine?
                    var selfcalls = LateStaticCallsLookup.GetSelfStaticCalls(cfg.Start);
                    if (selfcalls.Count == 0)
                    {
                        return;
                    }

                    // routine requires late static type?
                    if (selfcalls.Any(sm => sm.HasLateStaticBoundParam()))
                    {
                        caller.Flags |= RoutineFlags.UsesLateStatic;
                    }
                    else
                    {
                        foreach (var callee in selfcalls)
                        {
                            calls.Add(new KeyValuePair <SourceMethodSymbol, MethodSymbol>(caller, callee));
                        }
                    }
                }
            }, allowParallel: ConcurrentBuild);

            // process edges between caller and calles until we forward all the late static calls
            int forwarded;

            do
            {
                forwarded = 0;
                Parallel.ForEach(calls, edge =>
                {
                    if ((edge.Key.Flags & RoutineFlags.UsesLateStatic) == 0 && edge.Value.HasLateStaticBoundParam())
                    {
                        edge.Key.Flags |= RoutineFlags.UsesLateStatic;
                        Interlocked.Increment(ref forwarded);
                    }
                });
            } while (forwarded != 0);
        }