Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid some unnecessary static readonly arrays #72727

Merged
merged 4 commits into from
Jul 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ internal static partial class Version
{
[LibraryImport(Libraries.Version, EntryPoint = "GetFileVersionInfoExW", StringMarshalling = StringMarshalling.Utf16)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool GetFileVersionInfoEx(
internal static unsafe partial bool GetFileVersionInfoEx(
uint dwFlags,
string lpwstrFilename,
uint dwHandle,
uint dwLen,
IntPtr lpData);
void* lpData);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ internal static partial class Version
{
[LibraryImport(Libraries.Version, EntryPoint = "VerQueryValueW", StringMarshalling = StringMarshalling.Utf16)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool VerQueryValue(IntPtr pBlock, string lpSubBlock, out IntPtr lplpBuffer, out uint puLen);
internal static unsafe partial bool VerQueryValue(void* pBlock, string lpSubBlock, out void* lplpBuffer, out uint puLen);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,110 +12,83 @@ private unsafe FileVersionInfo(string fileName)
{
_fileName = fileName;

uint handle; // This variable is not used, but we need an out variable.
uint infoSize = Interop.Version.GetFileVersionInfoSizeEx(
(uint)Interop.Version.FileVersionInfoType.FILE_VER_GET_LOCALISED, _fileName, out handle);

uint infoSize = Interop.Version.GetFileVersionInfoSizeEx(Interop.Version.FileVersionInfoType.FILE_VER_GET_LOCALISED, _fileName, out _);
if (infoSize != 0)
{
byte[] mem = new byte[infoSize];
fixed (byte* memPtr = &mem[0])
void* memPtr = NativeMemory.Alloc(infoSize);
try
{
IntPtr memIntPtr = new IntPtr((void*)memPtr);
if (Interop.Version.GetFileVersionInfoEx(
(uint)Interop.Version.FileVersionInfoType.FILE_VER_GET_LOCALISED | (uint)Interop.Version.FileVersionInfoType.FILE_VER_GET_NEUTRAL,
_fileName,
0U,
infoSize,
memIntPtr))
Interop.Version.FileVersionInfoType.FILE_VER_GET_LOCALISED | Interop.Version.FileVersionInfoType.FILE_VER_GET_NEUTRAL,
_fileName,
0U,
infoSize,
memPtr))
{
uint langid = GetVarEntry(memIntPtr);
if (!GetVersionInfoForCodePage(memIntPtr, ConvertTo8DigitHex(langid)))
{
// Some DLLs might not contain correct codepage information. In these cases we will fail during lookup.
// Explorer will take a few shots in dark by trying several specific lang-codepages
// (Explorer also randomly guesses 041D04B0=Swedish+CP_UNICODE and 040704B0=German+CP_UNICODE sometimes).
// We will try to simulate similar behavior here.
foreach (uint id in s_fallbackLanguageCodePages)
{
if (id != langid)
{
if (GetVersionInfoForCodePage(memIntPtr, ConvertTo8DigitHex(id)))
{
break;
}
}
}
}
// Some dlls might not contain correct codepage information, in which case the lookup will fail. Explorer will take
// a few shots in dark. We'll simulate similar behavior by falling back to the following lang-codepages.
uint lcp = GetLanguageAndCodePage(memPtr);
_ = GetVersionInfoForCodePage(memPtr, lcp.ToString("X8")) ||
(lcp != 0x040904B0 && GetVersionInfoForCodePage(memPtr, "040904B0")) || // US English + CP_UNICODE
(lcp != 0x040904E4 && GetVersionInfoForCodePage(memPtr, "040904E4")) || // US English + CP_USASCII
(lcp != 0x04090000 && GetVersionInfoForCodePage(memPtr, "04090000")); // US English + unknown codepage
}
}
finally
{
NativeMemory.Free(memPtr);
}
}
}

// Some dlls might not contain correct codepage information,
// in which case the lookup will fail. Explorer will take
// a few shots in dark. We'll simulate similar behavior by
// falling back to the following lang-codepages:
private static readonly uint[] s_fallbackLanguageCodePages = new uint[]
{
0x040904B0, // US English + CP_UNICODE
0x040904E4, // US English + CP_USASCII
0x04090000 // US English + unknown codepage
};

private static string ConvertTo8DigitHex(uint value)
{
return value.ToString("X8");
}

private static unsafe Interop.Version.VS_FIXEDFILEINFO GetFixedFileInfo(IntPtr memPtr)
private static unsafe Interop.Version.VS_FIXEDFILEINFO GetFixedFileInfo(void* memPtr)
{
if (Interop.Version.VerQueryValue(memPtr, "\\", out IntPtr memRef, out _))
if (Interop.Version.VerQueryValue(memPtr, "\\", out void* memRef, out _))
{
return *(Interop.Version.VS_FIXEDFILEINFO*)memRef;
}

return default;
}

private static unsafe string GetFileVersionLanguage(IntPtr memPtr)
private static unsafe string GetFileVersionLanguage(void* memPtr)
{
uint langid = GetVarEntry(memPtr) >> 16;
uint langid = GetLanguageAndCodePage(memPtr) >> 16;

const int MaxLength = 256;
char* lang = stackalloc char[MaxLength];
int charsWritten = Interop.Kernel32.VerLanguageName(langid, lang, MaxLength);
return new string(lang, 0, charsWritten);
}

private static string GetFileVersionString(IntPtr memPtr, string name)
private static unsafe string GetFileVersionString(void* memPtr, string name)
{
if (Interop.Version.VerQueryValue(memPtr, name, out IntPtr memRef, out _))
if (Interop.Version.VerQueryValue(memPtr, name, out void* memRef, out _) &&
memRef is not null)
{
if (memRef != IntPtr.Zero)
{
return Marshal.PtrToStringUni(memRef)!;
}
return Marshal.PtrToStringUni((IntPtr)memRef)!;
}

return string.Empty;
}

private static uint GetVarEntry(IntPtr memPtr)
private static unsafe uint GetLanguageAndCodePage(void* memPtr)
{
if (Interop.Version.VerQueryValue(memPtr, "\\VarFileInfo\\Translation", out IntPtr memRef, out _))
if (Interop.Version.VerQueryValue(memPtr, "\\VarFileInfo\\Translation", out void* memRef, out _))
{
return (uint)((Marshal.ReadInt16(memRef) << 16) + Marshal.ReadInt16((IntPtr)((long)memRef + 2)));
return
(uint)((*(ushort*)memRef << 16) +
*((ushort*)memRef + 1));
}

return 0x040904E4;
return 0x040904E4; // US English + CP_USASCII
}

//
// This function tries to find version information for a specific codepage.
// Returns true when version information is found.
//
private bool GetVersionInfoForCodePage(IntPtr memIntPtr, string codepage)
private unsafe bool GetVersionInfoForCodePage(void* memIntPtr, string codepage)
{
Span<char> stackBuffer = stackalloc char[256];

Expand Down Expand Up @@ -144,24 +117,18 @@ private bool GetVersionInfoForCodePage(IntPtr memIntPtr, string codepage)
_productBuild = (int)HIWORD(ffi.dwProductVersionLS);
_productPrivate = (int)LOWORD(ffi.dwProductVersionLS);

_isDebug = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_DEBUG) != 0;
_isPatched = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_PATCHED) != 0;
_isPrivateBuild = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_PRIVATEBUILD) != 0;
_isPreRelease = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_PRERELEASE) != 0;
_isSpecialBuild = (ffi.dwFileFlags & (uint)Interop.Version.FileVersionInfo.VS_FF_SPECIALBUILD) != 0;
_isDebug = (ffi.dwFileFlags & Interop.Version.FileVersionInfo.VS_FF_DEBUG) != 0;
_isPatched = (ffi.dwFileFlags & Interop.Version.FileVersionInfo.VS_FF_PATCHED) != 0;
_isPrivateBuild = (ffi.dwFileFlags & Interop.Version.FileVersionInfo.VS_FF_PRIVATEBUILD) != 0;
_isPreRelease = (ffi.dwFileFlags & Interop.Version.FileVersionInfo.VS_FF_PRERELEASE) != 0;
_isSpecialBuild = (ffi.dwFileFlags & Interop.Version.FileVersionInfo.VS_FF_SPECIALBUILD) != 0;

// fileVersion is chosen based on best guess. Other fields can be used if appropriate.
return (_fileVersion != string.Empty);
}

private static uint HIWORD(uint dword)
{
return (dword >> 16) & 0xffff;
}
private static uint HIWORD(uint dword) => (dword >> 16) & 0xffff;

private static uint LOWORD(uint dword)
{
return dword & 0xffff;
}
private static uint LOWORD(uint dword) => dword & 0xffff;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,13 @@ namespace System.Net.Http
/// </summary>
internal struct MultiProxy
{
private static readonly char[] s_proxyDelimiters = { ';', ' ', '\n', '\r', '\t' };
private readonly FailedProxyCache? _failedProxyCache;
private readonly Uri[]? _uris;
private readonly string? _proxyConfig;
private readonly bool _secure;
private int _currentIndex;
private Uri? _currentUri;

public static MultiProxy Empty => new MultiProxy(null, Array.Empty<Uri>());

private MultiProxy(FailedProxyCache? failedProxyCache, Uri[] uris)
{
_failedProxyCache = failedProxyCache;
Expand All @@ -41,6 +38,8 @@ private MultiProxy(FailedProxyCache failedProxyCache, string proxyConfig, bool s
_currentUri = null;
}

public static MultiProxy Empty => new MultiProxy(null, Array.Empty<Uri>());

/// <summary>
/// Parses a WinHTTP proxy config into a MultiProxy instance.
/// </summary>
Expand Down Expand Up @@ -198,6 +197,7 @@ private static bool TryParseProxyConfigPart(ReadOnlySpan<char> proxyString, bool
{
const int SECURE_FLAG = 1;
const int INSECURE_FLAG = 2;
const string ProxyDelimiters = "; \n\r\t";

int wantedFlag = secure ? SECURE_FLAG : INSECURE_FLAG;
int originalLength = proxyString.Length;
Expand All @@ -206,7 +206,7 @@ private static bool TryParseProxyConfigPart(ReadOnlySpan<char> proxyString, bool
{
// Skip any delimiters.
int iter = 0;
while (iter < proxyString.Length && Array.IndexOf(s_proxyDelimiters, proxyString[iter]) >= 0)
while (iter < proxyString.Length && ProxyDelimiters.Contains(proxyString[iter]))
{
++iter;
}
Expand Down Expand Up @@ -245,7 +245,7 @@ private static bool TryParseProxyConfigPart(ReadOnlySpan<char> proxyString, bool
}

// Find the next delimiter, or end of string.
iter = proxyString.IndexOfAny(s_proxyDelimiters);
iter = proxyString.IndexOfAny(ProxyDelimiters);
if (iter < 0)
{
iter = proxyString.Length;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,11 @@ public bool SendChunked
set => EntitySendFormat = value ? EntitySendFormat.Chunked : EntitySendFormat.ContentLength;
}

// We MUST NOT send message-body when we send responses with these Status codes
private static readonly int[] s_noResponseBody = { 100, 101, 204, 205, 304 };

private static bool CanSendResponseBody(int responseCode)
{
for (int i = 0; i < s_noResponseBody.Length; i++)
{
if (responseCode == s_noResponseBody[i])
{
return false;
}
}
return true;
}

private static bool CanSendResponseBody(int responseCode) =>
// We MUST NOT send message-body when we send responses with these Status codes
responseCode is not (100 or 101 or 204 or 205 or 304);

public long ContentLength64
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,9 @@ internal HttpListenerRequest(HttpListenerContext context)
_version = HttpVersion.Version10;
}

private static readonly char[] s_separators = new char[] { ' ' };

internal void SetRequestLine(string req)
{
string[] parts = req.Split(s_separators, 3);
string[] parts = req.Split(' ', 3);
if (parts.Length != 3)
{
_context.ErrorMessage = "Invalid request line (parts).";
Expand Down
13 changes: 6 additions & 7 deletions src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ public sealed class Cookie

internal static readonly char[] PortSplitDelimiters = new char[] { ' ', ',', '\"' };
// Space (' ') should be reserved as well per RFCs, but major web browsers support it and some web sites use it - so we support it too
internal static readonly char[] ReservedToName = new char[] { '\t', '\r', '\n', '=', ';', ',' };
internal static readonly char[] ReservedToValue = new char[] { ';', ',' };
internal const string ReservedToName = "\t\r\n=;,";

private string m_comment = string.Empty; // Do not rename (binary serialization)
private Uri? m_commentUri; // Do not rename (binary serialization)
Expand Down Expand Up @@ -239,7 +238,7 @@ internal bool InternalSetName(string? value)
|| value.StartsWith('$')
|| value.StartsWith(' ')
|| value.EndsWith(' ')
|| value.IndexOfAny(ReservedToName) >= 0)
|| value.AsSpan().IndexOfAny(ReservedToName) >= 0)
{
m_name = string.Empty;
return false;
Expand Down Expand Up @@ -347,7 +346,7 @@ internal bool VerifySetDefaults(CookieVariant variant, Uri uri, bool isLocalDoma
m_name.StartsWith('$') ||
m_name.StartsWith(' ') ||
m_name.EndsWith(' ') ||
m_name.IndexOfAny(ReservedToName) >= 0)
m_name.AsSpan().IndexOfAny(ReservedToName) >= 0)
{
if (shouldThrow)
{
Expand All @@ -358,7 +357,7 @@ internal bool VerifySetDefaults(CookieVariant variant, Uri uri, bool isLocalDoma

// Check the value
if (m_value == null ||
(!(m_value.Length > 2 && m_value.StartsWith('\"') && m_value.EndsWith('\"')) && m_value.IndexOfAny(ReservedToValue) >= 0))
(!(m_value.Length > 2 && m_value.StartsWith('\"') && m_value.EndsWith('\"')) && m_value.AsSpan().IndexOfAny(';', ',') >= 0))
{
if (shouldThrow)
{
Expand All @@ -369,7 +368,7 @@ internal bool VerifySetDefaults(CookieVariant variant, Uri uri, bool isLocalDoma

// Check Comment syntax
if (Comment != null && !(Comment.Length > 2 && Comment.StartsWith('\"') && Comment.EndsWith('\"'))
&& (Comment.IndexOfAny(ReservedToValue) >= 0))
&& (Comment.AsSpan().IndexOfAny(';', ',') >= 0))
{
if (shouldThrow)
{
Expand All @@ -380,7 +379,7 @@ internal bool VerifySetDefaults(CookieVariant variant, Uri uri, bool isLocalDoma

// Check Path syntax
if (Path != null && !(Path.Length > 2 && Path.StartsWith('\"') && Path.EndsWith('\"'))
&& (Path.IndexOfAny(ReservedToValue) >= 0))
&& (Path.AsSpan().IndexOfAny(';', ',') != -1))
{
if (shouldThrow)
{
Expand Down
18 changes: 7 additions & 11 deletions src/libraries/System.Private.CoreLib/src/System/Convert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,9 @@ public static partial class Convert
// Need to special case Enum because typecode will be underlying type, e.g. Int32
private static readonly Type EnumType = typeof(Enum);

internal static readonly char[] base64Table = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '+', '/', '=' };
internal const string Base64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

private const int base64LineBreakPosition = 76;
private const int Base64LineBreakPosition = 76;

#if DEBUG
static Convert()
Expand Down Expand Up @@ -2473,14 +2469,14 @@ private static unsafe int ConvertToBase64Array(char* outChars, byte* inData, int
// Convert three bytes at a time to base64 notation. This will consume 4 chars.
int i;

// get a pointer to the base64Table to avoid unnecessary range checking
fixed (char* base64 = &base64Table[0])
// get a pointer to the Base64Table to avoid unnecessary range checking
fixed (char* base64 = Base64Table)
{
for (i = offset; i < calcLength; i += 3)
{
if (insertLineBreaks)
{
if (charcount == base64LineBreakPosition)
if (charcount == Base64LineBreakPosition)
{
outChars[j++] = '\r';
outChars[j++] = '\n';
Expand All @@ -2498,7 +2494,7 @@ private static unsafe int ConvertToBase64Array(char* outChars, byte* inData, int
// Where we left off before
i = calcLength;

if (insertLineBreaks && (lengthmod3 != 0) && (charcount == base64LineBreakPosition))
if (insertLineBreaks && (lengthmod3 != 0) && (charcount == Base64LineBreakPosition))
{
outChars[j++] = '\r';
outChars[j++] = '\n';
Expand Down Expand Up @@ -2536,7 +2532,7 @@ private static int ToBase64_CalculateAndValidateOutputLength(int inputLength, bo

if (insertLineBreaks)
{
(uint newLines, uint remainder) = Math.DivRem(outlen, base64LineBreakPosition);
(uint newLines, uint remainder) = Math.DivRem(outlen, Base64LineBreakPosition);
if (remainder == 0)
{
--newLines;
Expand Down
Loading