diff --git a/src/coreclr/inc/CrstTypeTool.cs b/src/coreclr/inc/CrstTypeTool/CrstTypeTool.cs similarity index 82% rename from src/coreclr/inc/CrstTypeTool.cs rename to src/coreclr/inc/CrstTypeTool/CrstTypeTool.cs index b161d13f7273c..5db0a5527dae2 100644 --- a/src/coreclr/inc/CrstTypeTool.cs +++ b/src/coreclr/inc/CrstTypeTool/CrstTypeTool.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // @@ -6,7 +6,7 @@ // acquired before or after other Crst types) into a header file that defines a enum to describe each Crst // type and tables that map type to numerical ranking and a string based name. // -// To use the tool, run "csc.exe CrstTypeTool.cs" and run the resulting executable. +// To use the tool, run "dotnet run --project src/coreclr/inc/CrstTypeTool/" from repo root. // // The Crst type definition file is written in a very simple language. Comments begin with '//' and continue // to the end of the line. All remaining tokens after comment removal are simply sequences of non-whitespace @@ -51,11 +51,11 @@ using System.Text.RegularExpressions; // The main application class containing the program entry point. -class CrstTypeTool +internal sealed partial class CrstTypeTool { // A hash containing every Crst type defined by the input .def file along with its attributes. Keyed by // Crst type name (which is case sensitive and doesn't include the 'Crst' enum prefix). - Dictionary m_crsts = new Dictionary(); + private Dictionary m_crsts = new Dictionary(); // The program entry point. public static int Main() @@ -63,16 +63,8 @@ public static int Main() try { // Calculate the filenames of the input and output files. - string inputFile = "CrstTypes.def"; - string outputFile = "crsttypes_generated.h"; - - // A common error is to forget to check out the crsttypes_generated.h file first. Handle this case specially - // so we can give a good error message. - if (File.Exists(outputFile) && (File.GetAttributes(outputFile) & FileAttributes.ReadOnly) != 0) - { - Console.WriteLine(outputFile + " is read-only, you must check it out of TFS/SD first"); - return 2; - } + string inputFile = Path.Combine("src", "coreclr", "inc", "CrstTypes.def"); + string outputFile = Path.Combine("src", "coreclr", "inc", "crsttypes_generated.h"); // Create an instance of our application class to store state in (specifically the collection of // Crst type definitions). @@ -114,7 +106,7 @@ public static int Main() } // Emit the crsttypes_generated.h output file. - void WriteHeaderFile(string fileName) + private void WriteHeaderFile(string fileName) { FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None); StreamWriter writer = new StreamWriter(stream); @@ -141,7 +133,7 @@ void WriteHeaderFile(string fileName) writer.WriteLine(); writer.WriteLine("// This file describes the range of Crst types available and their mapping to a numeric level (used by the"); writer.WriteLine("// runtime in debug mode to validate we're deadlock free). To modify these settings edit the"); - writer.WriteLine("// file:CrstTypes.def file and run the clr\\artifacts\\CrstTypeTool utility to generate a new version of this file."); + writer.WriteLine("// file:CrstTypes.def file and run the .\\CrstTypeTool utility to generate a new version of this file."); writer.WriteLine(); // Emit the CrstType enum to define a value for each crst type (along with the kNumberOfCrstTypes @@ -173,8 +165,7 @@ void WriteHeaderFile(string fileName) foreach (CrstType crst in crsts) { string crstLine = " " + crst.Level + ","; - crstLine = crstLine + new string(' ', 16 - crstLine.Length); - writer.WriteLine(crstLine + "// Crst" + crst.Name); + writer.WriteLine(crstLine.PadRight(16) + "// Crst" + crst.Name); } writer.WriteLine("};"); writer.WriteLine(); @@ -220,7 +211,7 @@ void WriteHeaderFile(string fileName) // Perform checking of the Crst type definitions we've read just read. Various forms of logic error are // scanned for including cycles in the dependency graph. Returns true if no errors are found. If false is // returned a descriptive error message will have already been written to the console. - bool ValidateCrsts() + private bool ValidateCrsts() { // Look at each Crst type definition in turn. foreach (CrstType crst in m_crsts.Values) @@ -228,7 +219,7 @@ bool ValidateCrsts() // Catch Crst types that are referenced but never defined. if (!crst.Defined) { - Console.WriteLine(String.Format("Error: CrstType 'Crst{0}' is referenced without being defined", + Console.WriteLine(string.Format("Error: CrstType 'Crst{0}' is referenced without being defined", crst.Name)); return false; } @@ -238,7 +229,7 @@ bool ValidateCrsts() if (crst.Level == CrstType.CrstUnordered && (crst.AcquiredBeforeList.Count > 0 || crst.Group != null)) { - Console.WriteLine(String.Format("Error: CrstType 'Crst{0}' is declared as both unordered and acquired before 'Crst{1}'", + Console.WriteLine(string.Format("Error: CrstType 'Crst{0}' is declared as both unordered and acquired before 'Crst{1}'", crst.Name, crst.AcquiredBeforeList[0].Name)); return false; } @@ -247,7 +238,7 @@ bool ValidateCrsts() // indicates an ordering). if (crst.Level == CrstType.CrstUnordered && crst.Group != null) { - Console.WriteLine(String.Format("Error: CrstType 'Crst{0}' is declared as both unordered and in the same level as another CrstType", + Console.WriteLine(string.Format("Error: CrstType 'Crst{0}' is declared as both unordered and in the same level as another CrstType", crst.Name)); return false; } @@ -255,7 +246,7 @@ bool ValidateCrsts() // Catch the simple cycle where the Crst type depends on itself. if (crst.AcquiredBeforeList.Contains(crst)) { - Console.WriteLine(String.Format("Error: CrstType 'Crst{0}' is declared as being acquired before itself", + Console.WriteLine(string.Format("Error: CrstType 'Crst{0}' is declared as being acquired before itself", crst.Name)); return false; } @@ -264,10 +255,10 @@ bool ValidateCrsts() List cycleList = new List(); if (FindCycle(crst, crst, cycleList)) { - Console.WriteLine(String.Format("Error: CrstType 'Crst{0}' is involved in a dependency cycle with the following CrstTypes:", + Console.WriteLine(string.Format("Error: CrstType 'Crst{0}' is involved in a dependency cycle with the following CrstTypes:", crst.Name)); foreach (CrstType cycleCrst in cycleList) - Console.WriteLine(String.Format(" Crst{0}", cycleCrst.Name)); + Console.WriteLine(string.Format(" Crst{0}", cycleCrst.Name)); return false; } } @@ -286,10 +277,10 @@ bool ValidateCrsts() List cycleList = new List(); if (FindCycle(crst, crst, cycleList)) { - Console.WriteLine(String.Format("Error: CrstType 'Crst{0}' is involved in a dependency cycle with the following CrstTypes:", + Console.WriteLine(string.Format("Error: CrstType 'Crst{0}' is involved in a dependency cycle with the following CrstTypes:", crst.Name)); foreach (CrstType cycleCrst in cycleList) - Console.WriteLine(String.Format(" Crst{0}", cycleCrst)); + Console.WriteLine(string.Format(" Crst{0}", cycleCrst)); Console.WriteLine("Note that the cycle was detected only after 'SameLevelAs' processing was performed so some CrstType dependencies are implied by peer CrstTypes"); return false; } @@ -306,7 +297,7 @@ bool ValidateCrsts() // Note that this algorithm is not designed to detect general cycles in the graph, only those that involve // the 'rootCrst' directly. This is somewhat inefficient but gives us a simple way to generate clear error // messages. - bool FindCycle(CrstType rootCrst, CrstType currCrst, List cycleList) + private static bool FindCycle(CrstType rootCrst, CrstType currCrst, List cycleList) { // Add the current Crst type to the list of those we've seen. cycleList.Add(currCrst); @@ -338,7 +329,7 @@ bool FindCycle(CrstType rootCrst, CrstType currCrst, List cycleList) // (Crst types that may only be acquired if a lower type is not already held). // **** NOTE: The leveling process is destructive in that we will lose all dependency information from the // Crst type definitions during the course of the algorithm. - void LevelCrsts() + private void LevelCrsts() { // Note that Crst type dependency rules have been normalized (by the input parser) so that all // AcquiredBefore/AcquiredAfter relationships have been reduced to AcquiredBefore relationships (i.e. @@ -442,7 +433,7 @@ void LevelCrsts() // call to ValidateCrsts(), so this check is pure paranoia. if (!madeProgress) { - Console.WriteLine(String.Format("{0} unsorted remain", unsorted)); + Console.WriteLine(string.Format("{0} unsorted remain", unsorted)); throw new Exception("Cycle detected trying to assign level " + currLevel.ToString()); } @@ -464,7 +455,7 @@ void LevelCrsts() // Predicate method used with List.FindAll() to locate Crst types that haven't had their rank assigned // yet. - static bool Unleveled(CrstType crst) + private static bool Unleveled(CrstType crst) { return crst.Level == CrstType.CrstUnassigned; } @@ -473,19 +464,22 @@ static bool Unleveled(CrstType crst) // Class used to parse a CrstTypes.def file into a dictionary of Crst type definitions. It uses a simple lexer // that removes comments then forms tokens out of any consecutive non-whitespace characters. An equally simple // recursive descent parser forms Crst instances by parsing the token stream. -class TypeFileParser +internal sealed partial class TypeFileParser { // Remember the input file name and the dictionary we're meant to populate. - string m_typeFileName; - Dictionary m_crsts; + private string m_typeFileName; + private Dictionary m_crsts; // Compile regular expressions for detecting comments and tokens in the parser input. - Regex m_commentRegex = new Regex(@"//.*"); - Regex m_tokenRegex = new Regex(@"^(\s*(\S+)\s*)*"); + [GeneratedRegex(@"//.*")] + private static partial Regex CommentRegex(); + + [GeneratedRegex(@"^(\s*(\S+)\s*)*")] + private static partial Regex TokenRegex(); // Input is lexed into an array of tokens. We record the index of the token being currently parsed. - Token[] m_tokens; - int m_currToken; + private Token[] m_tokens; + private int m_currToken; // Parse the given file into Crst type definitions and place these definitions in the dictionary provided. // Syntax errors are signalled via ParseError derived exceptions. @@ -514,7 +508,7 @@ public void ParseFile(string typeFileName, Dictionary crsts) } // Parse a single Crst type definition. - void ParseCrst() + private void ParseCrst() { // The next token had better be an identifier (the Crst type name). Token token = NextToken(); @@ -524,12 +518,10 @@ void ParseCrst() // The Crst instance might already exist in the dictionary (forward references to a Crst type cause // these entries to auto-vivify). But in that case the entry better not be marked as 'Defined' which // would indicate a double declaration. - CrstType crst; - if (m_crsts.ContainsKey(token.Text)) + if (m_crsts.TryGetValue(token.Text, out CrstType crst)) { - crst = m_crsts[token.Text]; if (crst.Defined) - throw new ParseError(String.Format("Duplicate definition for CrstType '{0}'", token.Text), token); + throw new ParseError(string.Format("Duplicate definition for CrstType '{0}'", token.Text), token); } else { @@ -553,46 +545,46 @@ void ParseCrst() switch (token.Id) { - case KeywordId.AcquiredBefore: - // Simply parse the following list of Crst types into the current type's AcquiredBefore list. - ParseList(crst.AcquiredBeforeList); - break; - - case KeywordId.AcquiredAfter: - // AcquiredAfter is trickier. To make the ranking algorithm's life easier we actually - // normalize all rules to the AcquiredBefore form (see LevelCrsts() for the reasoning). So we - // capture the list of Crst types that follow the AcquiredAfter keyword and then append the - // current type to the AcquiredBefore list of each type found. - list = new List(); - ParseList(list); - foreach (CrstType priorCrst in list) - priorCrst.AcquiredBeforeList.Add(crst); - break; - - case KeywordId.SameLevelAs: - // Parse the following list of Crst types them let the CrstTypeGroup class handle the - // resulting updates to the type groups we're currently maintaining. See the comments for the - // CrstTypeGroup class for more details. - list = new List(); - ParseList(list); - foreach (CrstType sameLevelCrst in list) - CrstTypeGroup.Join(crst, sameLevelCrst); - break; - - case KeywordId.Unordered: - crst.Level = CrstType.CrstUnordered; - break; - - case KeywordId.End: - parsingCrst = false; - break; - - default: - throw new UnexpectedTokenError(token, - KeywordId.AcquiredBefore, - KeywordId.AcquiredAfter, - KeywordId.SameLevelAs, - KeywordId.Unordered); + case KeywordId.AcquiredBefore: + // Simply parse the following list of Crst types into the current type's AcquiredBefore list. + ParseList(crst.AcquiredBeforeList); + break; + + case KeywordId.AcquiredAfter: + // AcquiredAfter is trickier. To make the ranking algorithm's life easier we actually + // normalize all rules to the AcquiredBefore form (see LevelCrsts() for the reasoning). So we + // capture the list of Crst types that follow the AcquiredAfter keyword and then append the + // current type to the AcquiredBefore list of each type found. + list = new List(); + ParseList(list); + foreach (CrstType priorCrst in list) + priorCrst.AcquiredBeforeList.Add(crst); + break; + + case KeywordId.SameLevelAs: + // Parse the following list of Crst types them let the CrstTypeGroup class handle the + // resulting updates to the type groups we're currently maintaining. See the comments for the + // CrstTypeGroup class for more details. + list = new List(); + ParseList(list); + foreach (CrstType sameLevelCrst in list) + CrstTypeGroup.Join(crst, sameLevelCrst); + break; + + case KeywordId.Unordered: + crst.Level = CrstType.CrstUnordered; + break; + + case KeywordId.End: + parsingCrst = false; + break; + + default: + throw new UnexpectedTokenError(token, + KeywordId.AcquiredBefore, + KeywordId.AcquiredAfter, + KeywordId.SameLevelAs, + KeywordId.Unordered); } } } @@ -600,7 +592,7 @@ void ParseCrst() // Parse a list of Crst type names. Any other token terminates the list (without error and without // consuming that token from the stream). The list of tokens is returned as a list of corresponding // CrstTypes (which are auto-vivified in the output dictionary if they haven't been declared yet). - void ParseList(List list) + private void ParseList(List list) { // Parse tokens until we find a non-identifier. while (true) @@ -615,10 +607,7 @@ void ParseList(List list) } // Look up or add a new CrstType corresponding to this type name. - CrstType crst; - if (m_crsts.ContainsKey(token.Text)) - crst = m_crsts[token.Text]; - else + if (!m_crsts.TryGetValue(token.Text, out CrstType crst)) { crst = new CrstType(token.Text); m_crsts[crst.Name] = crst; @@ -630,21 +619,21 @@ void ParseList(List list) } // Lex the input file into an array of tokens. - void InitTokenStream() + private void InitTokenStream() { - StreamReader file = new StreamReader(m_typeFileName); - int lineNumber = 1; - List tokenList = new List(); + StreamReader file = new StreamReader(m_typeFileName); + int lineNumber = 1; + List tokenList = new List(); // Read the file a line at a time. string line; while ((line = file.ReadLine()) != null) { // Remove comments from the current line. - line = m_commentRegex.Replace(line, ""); + line = CommentRegex().Replace(line, ""); // Match all contiguous non-whitespace characters as individual tokens. - Match match = m_tokenRegex.Match(line); + Match match = TokenRegex().Match(line); if (match.Success) { // For each token captured build a token instance and record the token text and the file, line @@ -665,13 +654,13 @@ void InitTokenStream() } // Have we run out of tokens to parse? - bool IsEof() + private bool IsEof() { return m_currToken >= m_tokens.Length; } // Get the next token and throw an exception if we ran out. - Token NextToken() + private Token NextToken() { if (m_currToken >= m_tokens.Length) throw new UnexpectedEofError(); @@ -679,7 +668,7 @@ Token NextToken() } // Push the last token parsed back into the stream. - void UnwindToken() + private void UnwindToken() { if (m_currToken <= 0) throw new InvalidOperationException(); @@ -700,56 +689,49 @@ internal enum KeywordId } // Class encapsulating a single token captured from the input file. - internal class Token + internal sealed class Token { // Hash of keyword text to enum values. - static Dictionary s_keywords; + // No sense building complex finite state machines to improve the efficiency of + // keyword lexing here since the input file (and keyword set) is never going to be + // big enough to justify the extra work. + private static Dictionary s_keywords = + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { "crst", KeywordId.Crst }, + { "end", KeywordId.End }, + { "acquiredbefore", KeywordId.AcquiredBefore }, + { "acquiredafter", KeywordId.AcquiredAfter }, + { "unordered", KeywordId.Unordered }, + { "samelevelas", KeywordId.SameLevelAs } + }; // The characters comprising the text of the token from the input file. - string m_text; + public string Text { get; } // Where the token was found (for error messages). - string m_file; - int m_line; - int m_column; + private string m_file; + private int m_line; + private int m_column; // The ID of the keyword this token represents (or KeywordId.Id). - KeywordId m_id; - - // Static class initialization. - static Token() - { - // Populate the keyword hash. No sense building complex finite state machines to improve the - // efficiency of keyword lexing here since the input file (and keyword set) is never going to be - // big enough to justify the extra work. - s_keywords = new Dictionary(); - s_keywords.Add("crst", KeywordId.Crst); - s_keywords.Add("end", KeywordId.End); - s_keywords.Add("acquiredbefore", KeywordId.AcquiredBefore); - s_keywords.Add("acquiredafter", KeywordId.AcquiredAfter); - s_keywords.Add("unordered", KeywordId.Unordered); - s_keywords.Add("samelevelas", KeywordId.SameLevelAs); - } + public KeywordId Id { get; } public Token(string file, string text, int line, int column) { m_file = file; - m_text = text; + Text = text; m_line = line; m_column = column; - // Map token text to keyword ID. True keywords (not identifiers) are case insensitive so normalize - // the text to lower case before performing the keyword hash lookup. - string canonName = m_text.ToLower(); - if (s_keywords.ContainsKey(canonName)) - m_id = s_keywords[canonName]; + // Map token text to keyword ID. + if (s_keywords.TryGetValue(Text, out KeywordId value)) + Id = value; else - m_id = KeywordId.Id; + Id = KeywordId.Id; } - public string Text {get { return m_text; }} - public string Location {get { return String.Format("{0} line {1}, column {2}", m_file, m_line, m_column); }} - public KeywordId Id {get { return m_id; }} + public string Location => $"{m_file} line {m_line}, column {m_column}"; } // Base class for all syntax errors reported by the parser. @@ -758,48 +740,48 @@ internal class ParseError : Exception // A raw error message. public ParseError(string message) : base(message) - {} + { } // An error message tagged with a file, line and column (coming from an error token). public ParseError(string message, Token errorToken) - : base(String.Format("{0}: {1}", errorToken.Location, message)) - {} + : base(string.Format("{0}: {1}", errorToken.Location, message)) + { } // Produce a textual name for the given keyword type. protected static string IdToName(KeywordId id) { if (id == KeywordId.Id) return "a CrstType name"; - return String.Format("'{0}'", id.ToString()); + return string.Format("'{0}'", id.ToString()); } } // Syntax error used when an unexpected token is encountered which further lists the valid tokens that // would otherwise have been accepted. - internal class UnexpectedTokenError : ParseError + internal sealed class UnexpectedTokenError : ParseError { // Produce an unexpected token message with a file, line and column coming from an error token and // optionally the names of zero or more tokens that would have been accepted. public UnexpectedTokenError(Token errorToken, params KeywordId[] expected) : base(FormatErrorMessage(errorToken, expected)) - {} + { } - static string FormatErrorMessage(Token errorToken, KeywordId[] expected) + private static string FormatErrorMessage(Token errorToken, KeywordId[] expected) { - StringBuilder message = new StringBuilder(String.Format("Unexpected token '{0}' at {1}", + StringBuilder message = new StringBuilder(string.Format("Unexpected token '{0}' at {1}", errorToken.Text, errorToken.Location)); if (expected.Length == 0) { } else if (expected.Length == 1) { - message.Append(String.Format("; expected {0}", IdToName(expected[0]))); + message.Append(string.Format("; expected {0}", IdToName(expected[0]))); } else { message.Append("; expected one of "); for (int i = 0; i < expected.Length - 1; i++) - message.Append(String.Format("{0}, ", IdToName(expected[i]))); + message.Append(string.Format("{0}, ", IdToName(expected[i]))); message.Append(IdToName(expected[expected.Length - 1])); } @@ -809,62 +791,52 @@ static string FormatErrorMessage(Token errorToken, KeywordId[] expected) } // Syntax error used when we unexpectedly ran out of tokens. - internal class UnexpectedEofError : ParseError + internal sealed class UnexpectedEofError : ParseError { public UnexpectedEofError() : base("Unexpected end of file") - {} + { } } } // This class represents an instance of a Crst type. These are unqiuely identified by case-sensitive name (the // same as the enum name used in vm code, minus the 'Crst' prefix). -class CrstType : IComparable +internal sealed class CrstType : IComparable { // Special level constants used to indicate unordered Crst types or those types we haven't gotten around // to ranking yet. - public static readonly int CrstUnordered = -1; - public static readonly int CrstUnassigned = -2; + public const int CrstUnordered = -1; + public const int CrstUnassigned = -2; // Name of the type, e.g. "AppDomainCache" for the CrstAppDomainCache type. - string m_name; + public string Name { get; } // The numeric ranking assigned to this type. Starts as CrstUnassigned and then becomes either // CrstUnordered (while parsing the input file) or a number >= 0 (during LevelCrsts()). - int m_level; + public int Level { get; set; } = CrstUnassigned; // List of Crst types that can be legally acquired while this one is held. (AcquiredAfter relationships // are by switching the terms and adding to the second type's AcquiredBefore list). - List m_acquiredBeforeCrsts; + public List AcquiredBeforeList { get; set; } = new List(); // Either null if this Crst type is not in (or has not yet been determined to be in) a SameLevelAs // relationship or points to a CrstTypeGroup that records all the sibling types at the same level (that // have been discovered thus far during parsing). - CrstTypeGroup m_group; + public CrstTypeGroup Group { get; set; } // Set once a definition for this type has been discovered. Used to detect double definitions and types // referenced without definitions. - bool m_defined; + public bool Defined { get; set; } public CrstType(string name) { - m_name = name; - m_level = CrstUnassigned; - m_acquiredBeforeCrsts = new List(); - m_group = null; - m_defined = false; + Name = name; } - public string Name {get { return m_name; }} - public int Level {get { return m_level; } set { m_level = value; }} - public List AcquiredBeforeList {get { return m_acquiredBeforeCrsts; } set { m_acquiredBeforeCrsts = value; }} - public CrstTypeGroup Group {get { return m_group; } set { m_group = value; }} - public bool Defined {get {return m_defined; } set { m_defined = value; }} - // Helper used to sort CrstTypes. The sort order is lexical based on the type name. - public int CompareTo(object other) + public int CompareTo(CrstType other) { - return m_name.CompareTo(((CrstType)other).m_name); + return Name.CompareTo(other.Name); } } @@ -879,13 +851,13 @@ public int CompareTo(object other) // parsing has finished we are guaranteed to have discovered all the distinct, disjoint groups and to have // fully populated them with the transitive closure of all related types. We can them normalize all groups // members so they share the same AcquiredBefore relationships. -class CrstTypeGroup +internal sealed class CrstTypeGroup { // We record every group that has been formed so far. This makes normalizing all groups easier. - static List s_groups = new List(); + private static List s_groups = new List(); // Crst types that are members of the current group. There are no duplicates in this list. - List m_members = new List(); + private List m_members = new List(); // Declare a SameLevelAs relationship between the two Crst types given. Groups will be assigned, created // or merged as required to maintain our guarantees (each CrstType is a member of at most one group and @@ -967,7 +939,7 @@ public static void NormalizeAllRules() // Normalize this group. This involves adjusting the AcquiredBefore list of each member to be the union of // all such rules within the group. This step allows us to detect cycles in the dependency graph that // would otherwise remain hidden if we only examined the unnormalized AcquiredBefore rules. - void NormalizeRules() + private void NormalizeRules() { // This local will contain the union of all AcquiredBefore rules. List acquiredBeforeList = new List(); @@ -988,5 +960,5 @@ void NormalizeRules() crst.AcquiredBeforeList = acquiredBeforeList.GetRange(0, acquiredBeforeList.Count); } - public List Members {get { return m_members; }} + public List Members { get { return m_members; } } } diff --git a/src/coreclr/inc/CrstTypeTool/CrstTypeTool.csproj b/src/coreclr/inc/CrstTypeTool/CrstTypeTool.csproj new file mode 100644 index 0000000000000..19e3a46d17f1d --- /dev/null +++ b/src/coreclr/inc/CrstTypeTool/CrstTypeTool.csproj @@ -0,0 +1,8 @@ + + + + Exe + $(NetCoreAppToolCurrent) + + + diff --git a/src/coreclr/inc/corerror.xml b/src/coreclr/inc/corerror.xml index 68c9a1aa5dfb3..a9dd81fb2c077 100644 --- a/src/coreclr/inc/corerror.xml +++ b/src/coreclr/inc/corerror.xml @@ -1176,6 +1176,11 @@ This object belongs to a non-gc heap + + CORPROF_E_MODULE_IS_ENC + The module is EnC + + CORSEC_E_POLICY_EXCEPTION "PolicyException thrown." diff --git a/src/coreclr/inc/crsttypes_generated.h b/src/coreclr/inc/crsttypes_generated.h index 1d7fa67870104..f14fe2c7a37a6 100644 --- a/src/coreclr/inc/crsttypes_generated.h +++ b/src/coreclr/inc/crsttypes_generated.h @@ -10,7 +10,7 @@ // This file describes the range of Crst types available and their mapping to a numeric level (used by the // runtime in debug mode to validate we're deadlock free). To modify these settings edit the -// file:CrstTypes.def file and run the clr\artifacts\CrstTypeTool utility to generate a new version of this file. +// file:CrstTypes.def file and run the .\CrstTypeTool utility to generate a new version of this file. // Each Crst type is declared as a value in the following CrstType enum. enum CrstType diff --git a/src/coreclr/inc/genheaders.cs b/src/coreclr/inc/genheaders.cs deleted file mode 100644 index 3a39954937357..0000000000000 --- a/src/coreclr/inc/genheaders.cs +++ /dev/null @@ -1,231 +0,0 @@ -// 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.Xml; -using System.Xml.Schema; -using System.IO; - -public class GenerateHeaders { - - public static void Main(string[] args) { - - if (args.Length != 3) { - Console.WriteLine("Usage:genheaders XML-file header-file resource-file"); - return; - } - - ValidateXML(args[0]); - String Message=null; - String SymbolicName=null; - String NumericValue=null; - String tempheaderfile = "temp.h"; - String temprcfile = "temp.rc"; - - StreamWriter HSW=File.CreateText(tempheaderfile); - StreamWriter RSW=File.CreateText(temprcfile); - - int FaciltyUrt=0x13; - int SeveritySuccess=0; - int SeverityError=1; - - int minSR = MakeHresult(SeveritySuccess,FaciltyUrt,0); - int maxSR = MakeHresult(SeveritySuccess,FaciltyUrt,0xffff); - int minHR = MakeHresult(SeverityError,FaciltyUrt,0); - int maxHR = MakeHresult(SeverityError,FaciltyUrt,0xffff); - - PrintLicenseHeader(HSW); - PrintHeader(HSW); - PrintLicenseHeader(RSW); - PrintResourceHeader(RSW); - - XmlTextReader rdr = new XmlTextReader(args[0]); - rdr.WhitespaceHandling = WhitespaceHandling.None; - - while (rdr.Read()) { - - switch (rdr.NodeType) { - - case XmlNodeType.Element: - - if (rdr.Name.ToString() == "HRESULT") { - NumericValue=rdr.GetAttribute("NumericValue"); - } - if (rdr.Name.ToString() == "Message") { - Message = rdr.ReadString(); - } - if (rdr.Name.ToString() == "SymbolicName") { - SymbolicName = rdr.ReadString(); - } - - break; - - case XmlNodeType.EndElement: - if(rdr.Name.ToString() == "HRESULT"){ - - // For CLR Hresult's we take the last 4 digits as the resource strings. - - if ( (NumericValue.StartsWith("0x")) || (NumericValue.StartsWith("0X")) ) { - - String HexResult = NumericValue.Substring(2); - int num = int.Parse(HexResult, System.Globalization.NumberStyles.HexNumber); - - if ((num>minSR) && (num <= maxSR)) { - num = num & 0xffff; - HSW.WriteLine("#define " + SymbolicName + " SMAKEHR(0x" + num.ToString("x") + ")"); - } else if ((num>minHR) && (num <= maxHR)) { - num = num & 0xffff; - HSW.WriteLine("#define " + SymbolicName + " EMAKEHR(0x" + num.ToString("x") + ")"); - } else { - HSW.WriteLine("#define " + SymbolicName + " " + NumericValue ); - } - - - - } else { - HSW.WriteLine("#define " + SymbolicName + " " + NumericValue ); - } - - if (Message != null) { - RSW.Write("\tMSG_FOR_URT_HR(" + SymbolicName + ") "); - RSW.WriteLine(Message); - } - - SymbolicName = null; - NumericValue = null; - Message = null; - } - break; - - } - } - - PrintFooter(HSW); - PrintResourceFooter(RSW); - - HSW.Close(); - RSW.Close(); - - bool AreFilesEqual = false; - - if (File.Exists(args[1])) { - StreamReader sr1 = new StreamReader(tempheaderfile); - StreamReader sr2 = new StreamReader(args[1]); - AreFilesEqual = CompareFiles(sr1, sr2); - sr1.Close(); - sr2.Close(); - } - - if (!AreFilesEqual) { - File.Copy(tempheaderfile, args[1], true); - File.Copy(temprcfile, args[2], true); - } - - if (!File.Exists(args[2])) { - File.Copy(temprcfile, args[2], true); - } - - File.Delete(tempheaderfile); - File.Delete(temprcfile); - } - - private static void ValidateXML (String XMLFile) { - - // Set the validation settings on the XmlReaderSettings object. - XmlReaderSettings settings = new XmlReaderSettings(); - - settings.ValidationType = ValidationType.Schema; - settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema; - - settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack); - - // Create the XmlReader object. - XmlReader reader = XmlReader.Create(XMLFile, settings); - - // Parse the file. - - while (reader.Read()) { - } - } - - // Display any validation errors. - private static void ValidationCallBack(object sender, ValidationEventArgs e) { - Console.WriteLine("Validation Error: {0}", e.Message); - Environment.Exit(-1); - } - - private static void PrintLicenseHeader(StreamWriter SW) { - SW.WriteLine("// Licensed to the .NET Foundation under one or more agreements."); - SW.WriteLine("// The .NET Foundation licenses this file to you under the MIT license."); - SW.WriteLine(); - } - - private static void PrintHeader(StreamWriter SW) { - - SW.WriteLine("#ifndef __COMMON_LANGUAGE_RUNTIME_HRESULTS__"); - SW.WriteLine("#define __COMMON_LANGUAGE_RUNTIME_HRESULTS__"); - SW.WriteLine(); - SW.WriteLine("#include "); - SW.WriteLine(); - SW.WriteLine(); - SW.WriteLine("//"); - SW.WriteLine("//This file is AutoGenerated -- Do Not Edit by hand!!!"); - SW.WriteLine("//"); - SW.WriteLine("//Add new HRESULTS along with their corresponding error messages to"); - SW.WriteLine("//corerror.xml"); - SW.WriteLine("//"); - SW.WriteLine(); - SW.WriteLine("#ifndef FACILITY_URT"); - SW.WriteLine("#define FACILITY_URT 0x13"); - SW.WriteLine("#endif"); - SW.WriteLine("#ifndef EMAKEHR"); - SW.WriteLine("#define SMAKEHR(val) MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_URT, val)"); - SW.WriteLine("#define EMAKEHR(val) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_URT, val)"); - SW.WriteLine("#endif"); - SW.WriteLine(); - } - - private static void PrintFooter(StreamWriter SW) { - SW.WriteLine(); - SW.WriteLine(); - SW.WriteLine("#endif // __COMMON_LANGUAGE_RUNTIME_HRESULTS__"); - } - - private static void PrintResourceHeader(StreamWriter SW) { - SW.WriteLine("STRINGTABLE DISCARDABLE"); - SW.WriteLine("BEGIN"); - } - - private static void PrintResourceFooter(StreamWriter SW) { - SW.WriteLine("END"); - } - - private static bool CompareFiles(StreamReader sr1, StreamReader sr2) { - String line1,line2; - - while (true) { - line1 = sr1.ReadLine(); - line2 = sr2.ReadLine(); - - if ( (line1 == null) && (line2 == null) ) { - return true; - } - - if (line1 != line2) { - return false; - } - - } - - } - - private static int MakeHresult(int sev, int fac, int code) { - return ((sev<<31) | (fac<<16) | (code)); - } -} - - - - - - diff --git a/src/coreclr/inc/genheaders/genheaders.cs b/src/coreclr/inc/genheaders/genheaders.cs new file mode 100644 index 0000000000000..b30ec1ec8db1c --- /dev/null +++ b/src/coreclr/inc/genheaders/genheaders.cs @@ -0,0 +1,157 @@ +// 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.IO; +using System.Xml; +using System.Xml.Linq; +using System.Xml.Schema; + +if (args.Length != 3) +{ + Console.WriteLine("Usage:genheaders XML-file header-file resource-file"); + return; +} + +ValidateXML(args[0]); + +using StreamWriter HSW = File.CreateText(args[1]); +using StreamWriter RSW = File.CreateText(args[2]); + +int FaciltyUrt = 0x13; +int SeveritySuccess = 0; +int SeverityError = 1; + +int minSR = MakeHresult(SeveritySuccess, FaciltyUrt, 0); +int maxSR = MakeHresult(SeveritySuccess, FaciltyUrt, 0xffff); +int minHR = MakeHresult(SeverityError, FaciltyUrt, 0); +int maxHR = MakeHresult(SeverityError, FaciltyUrt, 0xffff); + +PrintLicenseHeader(HSW); +PrintHeader(HSW); +PrintLicenseHeader(RSW); +PrintResourceHeader(RSW); + +XDocument doc = XDocument.Load(args[0]); +foreach (XElement element in doc.Descendants("HRESULT")) +{ + string NumericValue = element.Attribute("NumericValue")!.Value; + string? Message = element.Element("Message")?.Value; + string? SymbolicName = element.Element("SymbolicName")?.Value; + + // For CLR Hresult's we take the last 4 digits as the resource strings. + + if (NumericValue.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + { + int num = int.Parse(NumericValue.AsSpan(2), System.Globalization.NumberStyles.HexNumber); + + if ((num > minSR) && (num <= maxSR)) + { + num &= 0xffff; + HSW.WriteLine("#define " + SymbolicName + " SMAKEHR(0x" + num.ToString("x") + ")"); + } + else if ((num > minHR) && (num <= maxHR)) + { + num &= 0xffff; + HSW.WriteLine("#define " + SymbolicName + " EMAKEHR(0x" + num.ToString("x") + ")"); + } + else + { + HSW.WriteLine("#define " + SymbolicName + " " + NumericValue); + } + } + else + { + HSW.WriteLine("#define " + SymbolicName + " " + NumericValue); + } + + if (Message != null) + { + RSW.Write("\tMSG_FOR_URT_HR(" + SymbolicName + ") "); + RSW.WriteLine(Message); + } +} + +PrintFooter(HSW); +PrintResourceFooter(RSW); + +void ValidateXML(string XMLFile) +{ + + // Set the validation settings on the XmlReaderSettings object. + XmlReaderSettings settings = new XmlReaderSettings(); + + settings.ValidationType = ValidationType.Schema; + settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema; + + settings.ValidationEventHandler += (s, e) => + { + Console.WriteLine("Validation Error: {0}", e.Message); + Environment.Exit(-1); + }; + + // Create the XmlReader object. + XmlReader reader = XmlReader.Create(XMLFile, settings); + + // Parse the file. + + while (reader.Read()) + { + } +} + +void PrintLicenseHeader(StreamWriter SW) +{ + SW.WriteLine("// Licensed to the .NET Foundation under one or more agreements."); + SW.WriteLine("// The .NET Foundation licenses this file to you under the MIT license."); + SW.WriteLine(); +} + +void PrintHeader(StreamWriter SW) +{ + + SW.WriteLine("#ifndef __COMMON_LANGUAGE_RUNTIME_HRESULTS__"); + SW.WriteLine("#define __COMMON_LANGUAGE_RUNTIME_HRESULTS__"); + SW.WriteLine(); + SW.WriteLine("#include "); + SW.WriteLine(); + SW.WriteLine(); + SW.WriteLine("//"); + SW.WriteLine("//This file is AutoGenerated -- Do Not Edit by hand!!!"); + SW.WriteLine("//"); + SW.WriteLine("//Add new HRESULTS along with their corresponding error messages to"); + SW.WriteLine("//corerror.xml"); + SW.WriteLine("//"); + SW.WriteLine(); + SW.WriteLine("#ifndef FACILITY_URT"); + SW.WriteLine("#define FACILITY_URT 0x13"); + SW.WriteLine("#endif"); + SW.WriteLine("#ifndef EMAKEHR"); + SW.WriteLine("#define SMAKEHR(val) MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_URT, val)"); + SW.WriteLine("#define EMAKEHR(val) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_URT, val)"); + SW.WriteLine("#endif"); + SW.WriteLine(); +} + +void PrintFooter(StreamWriter SW) +{ + SW.WriteLine(); + SW.WriteLine(); + SW.WriteLine("#endif // __COMMON_LANGUAGE_RUNTIME_HRESULTS__"); +} + +void PrintResourceHeader(StreamWriter SW) +{ + SW.WriteLine("STRINGTABLE DISCARDABLE"); + SW.WriteLine("BEGIN"); +} + +void PrintResourceFooter(StreamWriter SW) +{ + SW.WriteLine("END"); +} + +int MakeHresult(int sev, int fac, int code) +{ + return ((sev << 31) | (fac << 16) | (code)); +} diff --git a/src/coreclr/inc/genheaders/genheaders.csproj b/src/coreclr/inc/genheaders/genheaders.csproj new file mode 100644 index 0000000000000..cb978588aafeb --- /dev/null +++ b/src/coreclr/inc/genheaders/genheaders.csproj @@ -0,0 +1,9 @@ + + + + Exe + $(NetCoreAppToolCurrent) + enable + + + diff --git a/src/coreclr/pal/prebuilt/corerror/makecorerror.bat b/src/coreclr/pal/prebuilt/corerror/makecorerror.bat deleted file mode 100644 index 939404f75a5b9..0000000000000 --- a/src/coreclr/pal/prebuilt/corerror/makecorerror.bat +++ /dev/null @@ -1,10 +0,0 @@ -@if "%_echo%"=="" echo off -REM Licensed to the .NET Foundation under one or more agreements. -REM The .NET Foundation licenses this file to you under the MIT license. -setlocal - -csc ..\..\..\inc\genheaders.cs - -genheaders.exe ..\..\..\inc\corerror.xml ..\inc\corerror.h mscorurt.rc - -del genheaders.exe diff --git a/src/coreclr/pal/prebuilt/corerror/readme.md b/src/coreclr/pal/prebuilt/corerror/readme.md new file mode 100644 index 0000000000000..ee69a16018cfb --- /dev/null +++ b/src/coreclr/pal/prebuilt/corerror/readme.md @@ -0,0 +1,15 @@ +# Update corerror.h and mscorurt.rc + +Execute in repo root: + +### Windows: + +``` +.\dotnet.cmd run --project .\src\coreclr\inc\genheaders\ -- .\src\coreclr\inc\corerror.xml .\src\coreclr\pal\prebuilt\inc\corerror.h .\src\coreclr\pal\prebuilt\corerror\mscorurt.rc +``` + +### Unix: + +``` +./dotnet.sh run --project ./src/coreclr/inc/genheaders/ -- ./src/coreclr/inc/corerror.xml ./src/coreclr/pal/prebuilt/inc/corerror.h ./src/coreclr/pal/prebuilt/corerror/mscorurt.rc +``` diff --git a/src/coreclr/pal/prebuilt/corerror/readme.txt b/src/coreclr/pal/prebuilt/corerror/readme.txt deleted file mode 100644 index a21a72490976a..0000000000000 --- a/src/coreclr/pal/prebuilt/corerror/readme.txt +++ /dev/null @@ -1,7 +0,0 @@ -Steps to generate corerror.h for the Unix: - -Open Razzle window -tf edit ..\inc\corerror.h -tf edit mscorurt.rc -makecorerror.bat -tf undo any files that didn't get modified \ No newline at end of file diff --git a/src/coreclr/pal/prebuilt/inc/corerror.h b/src/coreclr/pal/prebuilt/inc/corerror.h index 0b475679050fd..7106a8bbf3361 100644 --- a/src/coreclr/pal/prebuilt/inc/corerror.h +++ b/src/coreclr/pal/prebuilt/inc/corerror.h @@ -213,7 +213,7 @@ #define CORDIAGIPC_E_UNKNOWN_ERROR EMAKEHR(0x1387) #define CORPROF_E_SUSPENSION_IN_PROGRESS EMAKEHR(0x1388) #define CORPROF_E_NOT_GC_OBJECT EMAKEHR(0x1389) -#define CORPROF_E_MODULE_IS_ENC EMAKEHR(0x138A) +#define CORPROF_E_MODULE_IS_ENC EMAKEHR(0x138a) #define CORSEC_E_POLICY_EXCEPTION EMAKEHR(0x1416) #define CORSEC_E_MIN_GRANT_FAIL EMAKEHR(0x1417) #define CORSEC_E_NO_EXEC_PERM EMAKEHR(0x1418)