| File: System\Xml\Xsl\IlGen\XmlILTrace.cs | Web Access |
| Project: src\runtime\src\libraries\System.Private.Xml\src\System.Private.Xml.csproj (System.Private.Xml) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Globalization; using System.IO; using System.Runtime.Versioning; using System.Security; using System.Xml; using System.Xml.Xsl.Qil; // This class is only for debug purposes so there is no need to have it in Retail builds #if DEBUG namespace System.Xml.Xsl.IlGen { /// <summary> /// Helper class that facilitates tracing of ILGen. /// </summary> internal static class XmlILTrace { private const int MAX_REWRITES = 200; /// <summary> /// Check environment variable in order to determine whether to write out trace files. This really should be a /// check of the configuration file, but System.Xml does not yet have a good tracing story. /// </summary> private static string? s_dirName; private static volatile bool s_alreadyCheckedEnabled; /// <summary> /// True if tracing has been enabled (environment variable set). /// </summary> public static bool IsEnabled { // SxS: This property poses potential SxS issue. However the class is used only in debug builds (it won't // get compiled into ret build) so it's OK to suppress the SxS warning. get { // If environment variable has not yet been checked, do so now if (!s_alreadyCheckedEnabled) { try { s_dirName = Environment.GetEnvironmentVariable("XmlILTrace"); } catch (SecurityException) { // If user does not have access to environment variables, tracing will remain disabled } s_alreadyCheckedEnabled = true; } return (s_dirName != null); } } /// <summary> /// If tracing is enabled, this method will delete the contents of "filename" in preparation for append /// operations. /// </summary> public static void PrepareTraceWriter(string fileName) { if (!IsEnabled) return; File.Delete(s_dirName + "\\" + fileName); } /// <summary> /// If tracing is enabled, this method will open a TextWriter over "fileName" and return it. Otherwise, /// null will be returned. /// </summary> public static TextWriter? GetTraceWriter(string fileName) { if (!IsEnabled) return null; return new StreamWriter(s_dirName + "\\" + fileName, true); } /// <summary> /// Serialize Qil tree to "fileName", in the directory identified by "dirName". /// </summary> public static void WriteQil(QilExpression qil, string fileName) { if (!IsEnabled) return; XmlWriter w = XmlWriter.Create(s_dirName + "\\" + fileName); try { WriteQil(qil, w); } finally { w.Close(); } } /// <summary> /// Trace ILGen optimizations and log them to "fileName". /// </summary> public static void TraceOptimizations(QilExpression qil, string fileName) { if (!IsEnabled) return; XmlWriter w = XmlWriter.Create(s_dirName + "\\" + fileName); w.WriteStartDocument(); w.WriteProcessingInstruction("xml-stylesheet", "href='qilo.xslt' type='text/xsl'"); w.WriteStartElement("QilOptimizer"); w.WriteAttributeString("timestamp", DateTime.Now.ToString(CultureInfo.InvariantCulture)); WriteQilRewrite(qil, w, null); try { // Then, rewrite the graph until "done" or some max value is reached. for (int i = 1; i < MAX_REWRITES; i++) { QilExpression qilTemp = (QilExpression)(new QilCloneVisitor(qil.Factory).Clone(qil)); XmlILOptimizerVisitor visitor = new XmlILOptimizerVisitor(qilTemp, !qilTemp.IsDebug); visitor.Threshold = i; qilTemp = visitor.Optimize(); // In debug code, ensure that QIL after N steps is correct QilValidationVisitor.Validate(qilTemp); // Trace the rewrite WriteQilRewrite(qilTemp, w, OptimizationToString(visitor.LastReplacement)); if (visitor.ReplacementCount < i) break; } } catch (Exception e) { if (!XmlException.IsCatchableException(e)) { throw; } w.WriteElementString("Exception", null, e.ToString()); throw; } finally { w.WriteEndElement(); w.WriteEndDocument(); w.Flush(); w.Close(); } } /// <summary> /// Serialize Qil tree to writer "w". /// </summary> private static void WriteQil(QilExpression qil, XmlWriter w) { QilXmlWriter qw = new QilXmlWriter(w); qw.ToXml(qil); } /// <summary> /// Serialize rewritten Qil tree to writer "w". /// </summary> private static void WriteQilRewrite(QilExpression qil, XmlWriter w, string? rewriteName) { w.WriteStartElement("Diff"); if (rewriteName != null) w.WriteAttributeString("rewrite", rewriteName); WriteQil(qil, w); w.WriteEndElement(); } /// <summary> /// Get friendly string description of an ILGen optimization. /// </summary> private static string OptimizationToString(int opt) { string s = Enum.GetName(typeof(XmlILOptimization), opt)!; if (s.StartsWith("Introduce", StringComparison.Ordinal)) { return string.Concat(s.AsSpan(9), " introduction"); } else if (s.StartsWith("Eliminate", StringComparison.Ordinal)) { return string.Concat(s.AsSpan(9), " elimination"); } else if (s.StartsWith("Commute", StringComparison.Ordinal)) { return string.Concat(s.AsSpan(7), " commutation"); } else if (s.StartsWith("Fold", StringComparison.Ordinal)) { return string.Concat(s.AsSpan(4), " folding"); } else if (s.StartsWith("Misc", StringComparison.Ordinal)) { return s.Substring(4); } return s; } } } #endif