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); }
/// <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); }
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 // } //} }
/// <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); }
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); }
public static void Analyse(DiagnosticBag diagnostics, SourceRoutineSymbol routine) { if (routine.ControlFlowGraph != null) // non-abstract method { new DiagnosingVisitor(diagnostics, routine) .VisitCFG(routine.ControlFlowGraph); } }
/// <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; }
/// <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); }
/// <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); }
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); }); }
internal FlowContext(TypeRefContext /*!*/ typeCtx, SourceRoutineSymbol routine) { Contract.ThrowIfNull(typeCtx); _typeCtx = typeCtx; _routine = routine; // _varsIndex = new Dictionary <VariableName, int>(); }
/// <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>()); } }
public BoundClassTypeRef(QualifiedName qname, SourceRoutineSymbol routine, SourceTypeSymbol self) { if (qname.IsReservedClassName) { throw new ArgumentException(); } _qname = qname; _routine = routine; _self = self; }
public static ImmutableArray <BoundVariable> BindLocals(SourceRoutineSymbol routine) { Contract.ThrowIfNull(routine); var visitor = new LocalsBinder(routine); visitor.VisitRoutine(); // return(visitor.BindLocalsCore().ToImmutableArray()); }
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); }
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); } }
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; }
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>"); }
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); }
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)); }
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); } }
/// <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)); } }