Пример #1
0
        public static List <IPhpOperation> Select(SourceRoutineSymbol routine)
        {
            var visitor = new OperationSelector();

            visitor.VisitCFG(routine.ControlFlowGraph);
            return(visitor._result);
        }
            public static HashSet <BoundCopyValue> TryGetUnnecessaryCopies(SourceRoutineSymbol routine)
            {
                var cfg      = routine.ControlFlowGraph;
                var analysis = new CopyAnalysis(cfg.FlowContext);

                analysis._blockToStateMap[cfg.Start] = new CopyAnalysisState(analysis.VariableCount);
                analysis._worklist.Enqueue(cfg.Start);
                while (analysis._worklist.TryDequeue(out var block))
                {
                    analysis.Accept(block);
                }

                HashSet <BoundCopyValue> result = analysis._lazyReturnCopies;  // analysis won't be used anymore, no need to copy the set

                foreach (var kvp in analysis._copyIndices)
                {
                    if (!analysis._neededCopies.Get(kvp.Value))
                    {
                        if (result == null)
                        {
                            result = new HashSet <BoundCopyValue>();
                        }

                        result.Add(kvp.Key);
                    }
                }

                return(result);
            }
Пример #3
0
        /// <summary>
        /// Creates new type context, flow context and flow state for the routine.
        /// </summary>
        public static FlowState CreateInitialState(SourceRoutineSymbol /*!*/ routine, FlowContext flowCtx = null)
        {
            Contract.ThrowIfNull(routine);

            // get or create typeCtx
            var typeCtx = routine.TypeRefContext;

            if (flowCtx == null)
            {
                // create FlowContext
                flowCtx = new FlowContext(typeCtx, routine);
            }

            // create FlowState
            var state = new FlowState(flowCtx);

            // handle input parameters type
            foreach (var p in routine.SourceParameters)
            {
                var local = state.GetLocalHandle(new VariableName(p.Name));
                var ptype = p.GetResultType(typeCtx);
                state.SetLocalType(local, ptype);
            }

            // $this
            if (routine.GetPhpThisVariablePlace() != null)
            {
                InitThisVar(flowCtx, state);
            }

            //
            return(state);
        }
Пример #4
0
        public CodeGenerator(ILBuilder il, PEModuleBuilder moduleBuilder, DiagnosticBag diagnostics, OptimizationLevel optimizations, bool emittingPdb,
                             NamedTypeSymbol container, IPlace contextPlace, IPlace thisPlace, SourceRoutineSymbol routine = null, IPlace locals = null, bool localsInitialized = false)
        {
            Contract.ThrowIfNull(il);
            Contract.ThrowIfNull(moduleBuilder);

            if (localsInitialized)
            {
                Debug.Assert(locals != null);
            }

            _il            = il;
            _moduleBuilder = moduleBuilder;
            _optimizations = optimizations;
            _diagnostics   = diagnostics;

            _localsPlaceOpt    = locals;
            _localsInitialized = localsInitialized;

            _emmittedTag = 0;

            _contextPlace = contextPlace;
            _thisPlace    = thisPlace;

            _factory = new DynamicOperationFactory(this, container);

            _emitPdbSequencePoints = emittingPdb;

            _routine = routine;

            if (routine != null)
            {
                il.SetInitialDebugDocument(routine.ContainingFile.SyntaxTree);
            }
        }
        public static void WriteRoutine(TextWriter output, SourceRoutineSymbol routine)
        {
            Contract.ThrowIfNull(output);
            Contract.ThrowIfNull(routine);

            var phpdoc = routine.PHPDocBlock;

            if (phpdoc == null)
            {
                return;
            }

            //var ps = routine.Parameters;

            // PHPDoc
            WriteSummary(output, phpdoc.Summary);

            var elements = phpdoc.Elements;

            for (int i = 0; i < elements.Length; i++)
            {
                // user parameters
                if (elements[i] is PHPDocBlock.ParamTag p)
                {
                    if (p.VariableName != null)
                    {
                        WriteParam(output, p.VariableName.TrimStart('$'), p.Description, p.TypeNames);
                    }
                }
                else if (elements[i] is PHPDocBlock.ReturnTag rtag)
                {
                    if (!string.IsNullOrWhiteSpace(rtag.Description))
                    {
                        output.WriteLine("<returns>{0}</returns>", XmlEncode(rtag.Description));
                    }
                }
                else if (elements[i] is PHPDocBlock.ExceptionTag ex)
                {
                    WriteException(output, ex.TypeNamesArray, ex.Description);
                }
            }

            // TODO: <exception> ... if any

            //// implicit parameters
            //foreach (var p in ps)
            //{
            //    if (p.IsImplicitlyDeclared)
            //    {
            //        if (SpecialParameterSymbol.IsContextParameter(p))
            //        {
            //            // WriteParam(p.MetadataName, PhpResources.XmlDoc_ContextParamDescription);
            //        }
            //    }
            //    else
            //    {
            //        break;  // implicit parameters are always at begining
            //    }
            //}
        }
Пример #6
0
        /// <summary>
        /// Creates new type context, flow context and flow state for the routine.
        /// </summary>
        public static FlowState CreateInitialState(SourceRoutineSymbol /*!*/ routine)
        {
            Contract.ThrowIfNull(routine);

            // create typeCtx
            var typeCtx = routine.TypeRefContext;

            // create FlowContext
            var flowCtx = new FlowContext(typeCtx, routine);

            // create FlowState
            var state = new FlowState(flowCtx);

            // handle input parameters type
            var parameters = routine.Parameters.OfType <SourceParameterSymbol>().ToImmutableArray();

            foreach (var p in parameters)
            {
                state.SetVar(p.Name, p.GetResultType(typeCtx));

                if (p.Syntax.PassedByRef)
                {
                    state.SetVarRef(p.Name);
                }
            }

            // $this
            if (routine.HasThis)
            {
                InitThisVar(flowCtx, state);
            }

            //
            return(state);
        }
Пример #7
0
        private LocalsBinder(SourceRoutineSymbol routine)
            : base(routine.Syntax)
        {
            _routine = routine;

            this.VisitLocal += this.HandleLocal;
        }
 void WriteRoutine(SourceRoutineSymbol routine)
 {
     if (routine.IsGlobalScope)
     {
         return;                         // global code have no XML annotation
     }
     WriteRoutine(CommentIdResolver.GetId(routine), routine);
 }
Пример #9
0
 public static void Analyse(DiagnosticBag diagnostics, SourceRoutineSymbol routine)
 {
     if (routine.ControlFlowGraph != null)   // non-abstract method
     {
         new DiagnosingVisitor(diagnostics, routine)
         .VisitCFG(routine.ControlFlowGraph);
     }
 }
Пример #10
0
        /// <summary>
        /// Copy ctor with different routine content (and TypeRefContext).
        /// Used for emitting in a context of a different routine (parameter initializer).
        /// </summary>
        public CodeGenerator(CodeGenerator cg, SourceRoutineSymbol routine)
            : this(cg._il, cg._moduleBuilder, cg._diagnostics, cg._optimizations, cg._emitPdbSequencePoints, routine.ContainingType, cg.ContextPlaceOpt, cg.ThisPlaceOpt, routine)
        {
            Contract.ThrowIfNull(routine);

            _emmittedTag    = cg._emmittedTag;
            _localsPlaceOpt = cg._localsPlaceOpt;
        }
Пример #11
0
        /// <summary>
        /// Generates analyzed method.
        /// </summary>
        void EmitMethodBody(SourceRoutineSymbol routine)
        {
            Contract.ThrowIfNull(routine);
            Debug.Assert(routine.ControlFlowGraph.Start.FlowState != null);

            var body = MethodGenerator.GenerateMethodBody(_moduleBuilder, routine, 0, null, _diagnostics, _emittingPdb);

            _moduleBuilder.SetMethodBody(routine, body);
        }
 public static void Add(
     this DiagnosticBag diagnostics,
     SourceRoutineSymbol routine,
     LangElement syntax,
     ErrorCode code,
     params object[] args)
 {
     Add(diagnostics, routine, syntax.Span.ToTextSpan(), code, args);
 }
Пример #13
0
        /// <summary>
        /// Initializes table of locals of given routine.
        /// </summary>
        public LocalsTable(SourceRoutineSymbol routine)
        {
            Contract.ThrowIfNull(routine);

            _routine = routine;

            //
            PopulateParameters();
        }
        public Edge AddEdge(SourceRoutineSymbol caller, SourceRoutineSymbol callee, CallSite callSite)
        {
            var edge = new Edge(caller, callee, callSite);

            AddRoutineEdge(caller, edge);
            AddRoutineEdge(callee, edge);

            return(edge);
        }
Пример #15
0
        private void DiagnoseRoutine(SourceRoutineSymbol routine)
        {
            Contract.ThrowIfNull(routine);

            if (routine.ControlFlowGraph != null)   // non-abstract method
            {
                var diagnosingVisitor = new DiagnosingVisitor(_diagnostics, routine);
                diagnosingVisitor.VisitCFG(routine.ControlFlowGraph);
            }
        }
 private void AddRoutineEdge(SourceRoutineSymbol routine, Edge edge)
 {
     _incidentEdges.AddOrUpdate(
         routine,
         _ => new ConcurrentBag <Edge>()
     {
         edge
     },
         (_, edges) => { edges.Add(edge); return(edges); });
 }
Пример #17
0
        internal FlowContext(TypeRefContext /*!*/ typeCtx, SourceRoutineSymbol routine)
        {
            Contract.ThrowIfNull(typeCtx);

            _typeCtx = typeCtx;
            _routine = routine;

            //
            _varsIndex = new Dictionary <VariableName, int>();
        }
Пример #18
0
        /// <summary>
        /// Resolves <see cref="INamedTypeSymbol"/> best fitting given type mask.
        /// </summary>
        internal NamedTypeSymbol GetTypeFromTypeRef(SourceRoutineSymbol routine, TypeRefMask typeMask)
        {
            if (routine.ControlFlowGraph.HasFlowState)
            {
                var ctx = routine.ControlFlowGraph.FlowContext;
                return(this.GetTypeFromTypeRef(ctx.TypeRefContext, typeMask));
            }

            throw new InvalidOperationException();
        }
 public IEnumerable <Edge> GetIncidentEdges(SourceRoutineSymbol routine)
 {
     if (_incidentEdges.TryGetValue(routine, out var edges))
     {
         return(edges);
     }
     else
     {
         return(Array.Empty <Edge>());
     }
 }
Пример #20
0
        public BoundClassTypeRef(QualifiedName qname, SourceRoutineSymbol routine, SourceTypeSymbol self)
        {
            if (qname.IsReservedClassName)
            {
                throw new ArgumentException();
            }

            _qname   = qname;
            _routine = routine;
            _self    = self;
        }
Пример #21
0
        public static ImmutableArray <BoundVariable> BindLocals(SourceRoutineSymbol routine)
        {
            Contract.ThrowIfNull(routine);

            var visitor = new LocalsBinder(routine);

            visitor.VisitRoutine();

            //
            return(visitor.BindLocalsCore().ToImmutableArray());
        }
Пример #22
0
        public static void Analyse(DiagnosticBag diagnostics, SourceRoutineSymbol routine)
        {
            //
            routine.GetDiagnostics(diagnostics);

            //
            if (routine.ControlFlowGraph != null)   // non-abstract method
            {
                new DiagnosticWalker <VoidStruct>(diagnostics, routine).VisitCFG(routine.ControlFlowGraph);
            }
        }
        public static void Add(
            this DiagnosticBag diagnostics,
            SourceRoutineSymbol routine,
            TextSpan span,
            ErrorCode code,
            params object[] args)
        {
            var tree     = routine.ContainingFile.SyntaxTree;
            var location = new SourceLocation(tree, span);

            diagnostics.Add(location, code, args);
        }
Пример #24
0
        private void AnalyzeandDiagnoseRoutine(SourceRoutineSymbol routine)
        {
            Contract.ThrowIfNull(routine);

            if (routine.ControlFlowGraph != null)   // non-abstract method
            {
                PhylDiagnosingVisitor diagnosingVisitor = new PhylDiagnosingVisitor(Engine, _diagnostics, routine);
                diagnosingVisitor.VisitCFG(routine.ControlFlowGraph);
                AdjacencyGraph <ControlFlowGraphVertex, ControlFlowGraphEdge> g = diagnosingVisitor.Graph;
                ControlFlowGraphs.TryAdd(routine, g);
            }
        }
Пример #25
0
        public static bool TryResolveFile(ISymbolProvider model, SourceRoutineSymbol routine, BoundExpression expr, out IPhpScriptTypeSymbol script)
        {
            script = null;

            if (expr.ConstantValue.TryConvertToString(out var path))
            {
                // include (path)
                script = model.ResolveFile(path);
            }
            else if (expr is BoundPseudoConst pc1 && pc1.ConstType == BoundPseudoConst.Types.File) // __FILE__
            {
                script = routine.ContainingFile;
            }
Пример #26
0
        void WriteRoutine(SourceRoutineSymbol routine)
        {
            var ps = routine.Parameters;

            //
            _writer.WriteLine($"<member name=\"{CommentIdResolver.GetId(routine)}\">");

            // PHPDoc
            var phpdoc = routine.PHPDocBlock;

            if (phpdoc != null)
            {
                WriteSummary(phpdoc.Summary);

                // user parameters
                foreach (var p in phpdoc.Params)
                {
                    // TODO: note the parameter type into Doc comment

                    if (p.VariableName != null)
                    {
                        WriteParam(p.VariableName.TrimStart('$'), p.Description, p.TypeNames);
                    }
                }
                var rtag = phpdoc.Returns;
                if (rtag != null && !string.IsNullOrWhiteSpace(rtag.Description))
                {
                    _writer.WriteLine("<returns>{0}</returns>", XmlEncode(rtag.Description));
                }
            }

            // TODO: <exception> ... if any

            //// implicit parameters
            //foreach (var p in ps)
            //{
            //    if (p.IsImplicitlyDeclared)
            //    {
            //        if (SpecialParameterSymbol.IsContextParameter(p))
            //        {
            //            // WriteParam(p.MetadataName, PhpResources.XmlDoc_ContextParamDescription);
            //        }
            //    }
            //    else
            //    {
            //        break;  // implicit parameters are always at begining
            //    }
            //}

            _writer.WriteLine("</member>");
        }
Пример #27
0
        public static void Add(
            this DiagnosticBag diagnostics,
            SourceRoutineSymbol routine,
            LangElement syntax,
            ErrorCode code,
            params object[] args)
        {
            // TODO: Reuse the existing one instead
            var tree     = routine.ContainingFile.SyntaxTree;
            var span     = syntax.Span;
            var location = new SourceLocation(tree, span.ToTextSpan());

            diagnostics.Add(location, code, args);
        }
Пример #28
0
        internal static MethodBody GenerateMethodBody(
            PEModuleBuilder moduleBuilder,
            SourceRoutineSymbol routine,
            int methodOrdinal,
            //ImmutableArray<LambdaDebugInfo> lambdaDebugInfo,
            //ImmutableArray<ClosureDebugInfo> closureDebugInfo,
            //StateMachineTypeSymbol stateMachineTypeOpt,
            VariableSlotAllocator variableSlotAllocatorOpt,
            DiagnosticBag diagnostics,
            //ImportChain importChainOpt,
            bool emittingPdb)
        {
            return(GenerateMethodBody(moduleBuilder, routine, (builder) =>
            {
                DiagnosticBag diagnosticsForThisMethod = DiagnosticBag.GetInstance();
                var optimization = moduleBuilder.Compilation.Options.OptimizationLevel;
                var codeGen = new CodeGenerator(routine, builder, moduleBuilder, diagnosticsForThisMethod, optimization, emittingPdb);

                //if (diagnosticsForThisMethod.HasAnyErrors())
                //{
                //    // we are done here. Since there were errors we should not emit anything.
                //    return null;
                //}

                // We need to save additional debugging information for MoveNext of an async state machine.
                //var stateMachineMethod = method as SynthesizedStateMachineMethod;
                //bool isStateMachineMoveNextMethod = stateMachineMethod != null && method.Name == WellKnownMemberNames.MoveNextMethodName;

                //if (isStateMachineMoveNextMethod && stateMachineMethod.StateMachineType.KickoffMethod.IsAsync)
                //{
                //    int asyncCatchHandlerOffset;
                //    ImmutableArray<int> asyncYieldPoints;
                //    ImmutableArray<int> asyncResumePoints;
                //    codeGen.Generate(out asyncCatchHandlerOffset, out asyncYieldPoints, out asyncResumePoints);

                //    var kickoffMethod = stateMachineMethod.StateMachineType.KickoffMethod;

                //    // The exception handler IL offset is used by the debugger to treat exceptions caught by the marked catch block as "user unhandled".
                //    // This is important for async void because async void exceptions generally result in the process being terminated,
                //    // but without anything useful on the call stack. Async Task methods on the other hand return exceptions as the result of the Task.
                //    // So it is undesirable to consider these exceptions "user unhandled" since there may well be user code that is awaiting the task.
                //    // This is a heuristic since it's possible that there is no user code awaiting the task.
                //    asyncDebugInfo = new Cci.AsyncMethodBodyDebugInfo(kickoffMethod, kickoffMethod.ReturnsVoid ? asyncCatchHandlerOffset : -1, asyncYieldPoints, asyncResumePoints);
                //}
                //else
                {
                    codeGen.Generate();
                }
            }, variableSlotAllocatorOpt, diagnostics, emittingPdb));
        }
Пример #29
0
        public static bool TryTransform(SourceRoutineSymbol routine)
        {
            if (routine.ControlFlowGraph != null)   // non-abstract method
            {
                var visitor = new TransformationVisitor <VoidStruct>(routine);
                visitor.VisitCFG(routine.ControlFlowGraph);

                return(visitor._cfgTransformationCount + visitor._rewriter.TransformationCount > 0);
            }
            else
            {
                return(false);
            }
        }
Пример #30
0
        /// <summary>
        /// Create naming context.
        /// </summary>
        public static NamingContext GetNamingContext(this SourceRoutineSymbol routine)
        {
            var node = (LangElement)routine?.Syntax;

            if (node != null)
            {
                return(GetNamingContext(node.ContainingNamespace, node.ContainingSourceUnit));
            }
            else
            {
                Debug.Fail("Invalid routine - does not have syntax node");
                return(new NamingContext(null));
            }
        }